原创 PowerData谢帮桂 PowerData
本文由PowerData谢帮桂贡献 姓名:谢帮桂 花名:谢帮桂 微信:xc606060\_ 年龄:90后 工作经验:5-10年 工作内容:数仓,数分 自我介绍:美联物业数仓负责人,主要负责数仓规划和数据开发,下方是作者帅照喔。
全文共 4914 个字,建议阅读 18 分钟
社区线下活动预告!
小伙伴们速速报名,6月17我们上海见!!!
活动地址:徐汇区南丹路169号 景莱酒店 2层
前言
Apache Doirs 2.0 Alpha1 版本已经实现了倒排索引功能,可以实现在千亿级数据中快速对中文关键字日志检索,实现日志监控,本文主要实践利用Datax进行日常Nginx日志导入到Doirs中进行日志分析测试,适合单机日志或文本采集分析场景。
组件版本
Apache Doirs 2.0 alpha1版本 DataX 最新版本
Doris 2.0 版本说明
Apache Doris 2.0.0 alpha1 版本是 2.0 系列的首个版本,包含了倒排索引、高并发点查询、冷热分层、Pipeline 执行引擎、全新查询优化器 Nereids 等众多重要特性,主要是作为最新特性的功能验证。因此建议在新的测试集群中部署 2.0.0 alpha1 版本进行测试,但不应部署在生产集群中。
版本重要特性:
- 半结构化数据存储与极速分析
- 全新倒排索引:支持全文检索以及更加高效的等值查询、范围查询
- 增加了字符串类型的全文检索支持英文、中文分词
- 支持字符串类型和字符串数组类型的全文检索
- 支持字符串、数值、日期时间类型的等值查询和范围查询
- 支持多个条件的逻辑组合,不仅支持 AND,还支持 OR 和 not
- 在 esrally http 日志基准测试中,与 Elasticsearch 相比效率更高:数据导入速度提高了 4 倍,存储资源消耗减少了80%,查询速度提高了 2 倍以上
参考文档:https://doris.apache.org/zh-C...
安装步骤
安装Doirs2.0 alpha1版本
linux某节点下输入
curl https://doris.apache.org/download-scripts/2.0.0-alpha1/download_x64_tsinghua.sh | sh
下载的文件夹里已经有编译好的FE和BE文件夹,分别同步到集群节点,修改fe和be的conf里配置就可以使用,直接按官网文档安装步骤进行部署。
安装Datax
直接官网下载编译,可以只编译需要的reader和writer的连接器,本文需要txtfilereader和 doriswriter。
详细过程
nginx日志格式
下面是Nginx access.log日志文件格式,包括error.log基本大差不差。
192.168.1.10 - - [30/Apr/2022:11:24:39 +0800] "GET /api/data HTTP/1.1" 200 438 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.82 Safari/537.36" "-" 192.168.1.10 - - [30/Apr/2022:11:25:32 +0800] "POST /login HTTP/1.1" 403 187 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.82 Safari/537.36" "-" 192.168.1.10 - - [30/Apr/2022:11:26:14 +0800] "GET /css/style.css HTTP/1.1" 304 0 "https://www.example.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.82 Safari/537.36" "-" 192.168.1.10 - - [30/Apr/2022:11:27:06 +0800] "GET /images/logo.png HTTP/1.1" 200 2048 "https://www.example.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.82 Safari/537.36" "-" 192.168.1.10 - - [30/Apr/2022:11:28:03 +0800] "GET / HTTP/1.1" 200 1234 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.82 Safari/537.36" "-" 192.168.1.10 - - [30/Apr/2022:11:29:17 +0800] "GET /products/123 HTTP/1.1" 404 0 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.82 Safari/537.36" "-" 192.168.1.10 - - [30/Apr/2022:11:30:29 +0800] "GET /about HTTP/1.1" 301 0 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.82 Safari/537.36" "-" 192.168.1.10 - - [30/Apr/2022:11:31:44 +0800] "GET /contact HTTP/1.1" 302 0 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.82 Safari/537.36" "-" 192.168.1.10 - - [30/Apr/2022:11:32:57 +0800] "GET /faq HTTP/1.1" 200 823 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.82 Safari/537.36" "-" 192.168.1.10 - - [30/Apr/2022:11:34:10 +0800] "GET /downloads/file.zip HTTP/1.1" 200 98432 "https://www.example.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.82 Safari/537.36" "-" 127.0.0.1 - - [03/May/2022:12:00:47 +0800] "GET /byhsyyfront/byPages/ HTTP/1.1" 304 0 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.4844.51 Safari/537.36" "-" "0.025" "0.025" 127.0.0.1 - - [03/May/2022:12:00:47 +0800] "GET /byhsyyGateway/byhsyySystem/verifyCode/getVerifyCode HTTP/1.1" 200 2178 "http://localhost:8881/byhsyyfront/byPages/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.4844.51 Safari/537.36" "-" "0.037" "0.037"
nginx的格式对应字段,具体可以在nginx配置需要的字段:
$remote_addr 客户端地址 $remote_user 客户端用户名称 $time_local 访问时间和时区 $request 请求的URI和HTTP协议 $status HTTP请求状态 $body_bytes_sent 发送给客户端文件内容大小 $http_referer url跳转来源 $http_user_agent 用户终端浏览器等信息 $http_host 请求地址,即浏览器中你输入的地址(IP或域名) $request_time 处理请求的总时间,包含了用户数据接收时间 $upstream_response_time 建立连接和从上游服务器接收响应主体的最后一个字节之间的时间 $upstream_connect_time 花费在与上游服务器建立连接上的时间 $upstream_header_time 建立连接和从上游服务器接收响应头的第一个字节之间的时间
找了一份187万行的Nginx日志,放在job目录测试
Doris建表
在Doirs中创建一个log\_text表
CREATE TABLE test.`log_test` ( `worker_id` VARCHAR ( 250 ) NULL COMMENT "节点ID", `time_index` VARCHAR ( 250 ) NULL COMMENT "时间索引", `log_text String NULL COMMENT "log详情" ) ENGINE = OLAP COMMENT "nginx日志测试" DISTRIBUTED BY HASH ( `worker_id` ) ;
注意:模型最好是选用DUPLICATE表,后面Nginx按天分割日志可以根据日期作为Doirs表的分区列进行表分区替换,使用DUPLICATE表的好处是导入时既不做聚合也不做去重,不用像UNIQUE表一样导入还要进行Compaction,提高性能。
编写DataX-json文件
创建一个datax的json文件,命名为log\_test.json
{ "core": { "transport": { "channel": { "speed": { } } } }, "job": { "setting": { "speed": { "channel" : 5 } }, "content": [ { "reader": { "name": "txtfilereader", "parameter": { "path": ["/app/wwwroot/MBDC/datax/job/access.log"], "encoding": "UTF-8", "column": [ { "index": 0, "type": "string" } ], "fieldDelimiter": "\t" } }, "writer": { "name": "doriswriter", "parameter": { "feLoadUrl": ["10.1.1.157:8030"], "beLoadUrl": ["10.1.1.154:8050","10.1.1.155:8050","10.1.1.156:8050"], "jdbcUrl": "jdbc:mysql://10.1.1.157:9030", "database": "test", "table": "log_test", "column": ["log_text"], "username": "root", "password": "123456", "postSql": [], "preSql": [], "loadProps": { "max_filter_ratio": "0", "columns": "worker_id='nginx_01',time_index=str_to_date(regexp_extract(log_text,'\\\\d{2}\/[A-Z][a-z]{2}\/\\\\d{4}:\\\\d{2}:\\\\d{2}:\\\\d{2}',0),'%d/%b/%Y:%H:%i:%s'),log_text" } } } } ] } }
参数解释:
1、core和job参数可根据实际调优,详看datax调优;
2、reader的path,配置具体Nginx的log路径。也可以使用*通配符替代,如/nginx/log/access\_*,默认会把路径下所有日志给读取,要注意读取的日志的结构必须一致,path如果配置多个,则datax会启动多线程进行读取,后期可以根据这个特性对Nginx日志进行更细时间粒度的分割,如按小时、分钟对Nginx日志进行分割,再用datax多路径多线程去抽取,对日志量大的服务器提高抽取速度,nginx日志分割配置如下例子:
// 直接在nginx配置文件中修改,即可生产按小时、分钟、秒的粒度日志分割 if ($time_iso8601 ~ "^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})") { set $year $1; set $month $2; set $day $3; set $hour $4; set $minutes $5; set $seconds $6; } access_log /var/logs/xxxx/access/xxxxx_xx_access_$year-$month-$day-hour-minutes-seconds.log main;
3、reader的column我们只写一个列,直接把整行日志信息读取到一个列,原因是Nginx的分隔符不好指定,有嵌套空格,如果用户的app日志结构化非常清晰,有固定分隔符,可以直接把列序号对应来配置,在分隔符不固定的情况下,可以使用这种方式;
4、reader的fieldDelimiter默认是','逗号,我们替换成制表符\t,无需分列;
5、writer的column我们也只定义一个"log\_text",这个必须和reader的column对应;
6、writer的columns和column是不一样的,columns是Doris Stream Load方式的参数,是对应到Doris表里的字段,而columns是可以使用Doris的函数对列进行转换的,利用这个特性,可以在Stream Load过程就直接实现对日志进行正则过滤、常量定义、清洗和where筛选,非常NICE!
"columns": " worker_id='nginx_01', time_index=str_to_date(regexp_extract(log_text,'\\\\d{2}\/[A-Z][a-z]{2}\/\\\\d{4}:\\\\d{2}:\\\\d{2}:\\\\d{2}',0),'%d/%b/%Y:%H:%i:%s'), log_text "
worker\_id我这里直接等于一个常量,用户其实可以根据etl脚本进行动态传参,方便识别日志是哪一台Nginx节点。
time\_index字段我利用正则函数+str\_to\_date()函数抽取Nginx日志里的日志时间,方便Doris表可以利用这个时间字段进行动态分区,这里注意\d在json文件里需加上转义符\\d。
log\_text则是我reader和writer定义的列;
7、max\_filter\_ratio,Doirs写入记录的错误容忍比率,0代表容忍0错误率,0.2代表允许容忍20%的错误率。
导入Doirs
在Datax的目录对已创建好的json文件执行导入命令:
./bin/datax.py --jvm="-Xms3G -Xmx3G -XX:-UseGCOverheadLimit" ./job/log_test.json
可以看到187万行的日志在单机和没调优的情况下花费1分钟的样子,jvm参数根据实际情况调整,默认是1G,如果不够会报OOM,详细参数参考Datax官网。
Doris表数据已经进来:
对数据行数验证:
数量一致。因为设置max\_filter\_ratio=0,写入错误Doris会同步返回错误信息url进行修改。
日志检索
测试服务器情况: 1FE 3BE 8C16G
Doris给日志表创建倒排索引
CREATE INDEX log_text ON test.log_test(log_text) USING INVERTED PROPERTIES("parser" = "english");
需求1,查询日志出现"POST"关键字的次数,用like方式:
SELECT count(1) FROM test.log_test WHERE log_text like '%POST%';
需求2,查询接口被访问次数,使用 MATCH\_ALL 和 MATCH\_ANY 关键字:
SELECT count(1) FROM test.log_test WHERE log_text MATCH_ANY '/estimateDetails'; SELECT count(1) FROM test.log_test WHERE log_text MATCH_ALL '/estimateDetails /dataDetails';
需求3,查询失败次数
SELECT count(1) FROM test.log_test WHERE log_text MATCH_ALL '401';
需求4,系统类型
SELECT count(1) FROM test.log_test WHERE log_text not like '%Win64%';
补充
另外,Apache Doris 也可以使用Json格式文本进行Stream Load导入,2.0还实现了动态表的Json格式进行传输,这里Datax我还没想好怎么适配动态Json传输到Doris里,理论上是把Json格式的文本日志每一行Json存进一个列,在Doris writer的loadProps里指定format:json 参数就可以了,有空的朋友可以试试这一种方式。
动态 Schema 表(实验性功能) 自动推断半结构化 JSON 数据的字段名称和类型 根据写入的数据动态拓展相应数据表的 Schema。 参考:https://doris.apache.org/docs...
总结
谈谈Datax,对日志进行采集为什么我不是选用ELK、Flume和Loki+Grafana等高可用和分布式的组件,一是Doirs在日志方面的外部生态拓展就DataX doriswriter和Filebeat+Logstash Doris Output Plugin,除了Filebeat+Logstash,我选我们这边常用的导数工具Datax了,二是ELK和Flume等组件对于我们公司埋点数据量来说太重了,需自己实现Http方式Sink到Doris进行调试,我们尽量秉承如无必要勿增实体原则,聚焦于效率使用现成组件。
DataX一个非常好的地方就是"开箱即用",编译完直接用,用完就关闭的特点,单机多线程批采集千万行日志,性能也非常不错,缺点就是不能断点续传和内存优化不够容易OOM,这个就需要人工进行调优了,Datax可以对节点资源进行参数控制,比单纯使用Http Strean load的方式更加容易性能管理,不管是DataX还是Http,本质还是使用了Doris 的Strean load方式实现,批存批导还能使用sql函数对列进行过滤和筛选,配合日志文件按时间间隔裁剪+Doris时间分区建表,可以微批对业务埋点日志进行ETL管理。
而不规则类型的日志的采集,DataX和Http Strean load方式都不适合,比如监控组件日志,通常ERROR时会带java堆栈信息的。
这种不规则的日志类型更适合用Filebeat+Logstash Doris Output Plugin更丰富的正则计算前后记录的方式进行采集,还有云场景和千亿级日志等场景,最好优选Flume等更加高可用的日志采集方式,这就大家在架构之间衡量做选择。
谈谈Apache Doris,Doris 2.0除了很多激动人心的功能就不细说了,可以去官网下载进行体验,在日志检索方面,未来配合监控组件可以在日志场景中大有可为,本次测试数据量200W左右远远达不到测试要求,只是体验一下功能和提供给日志量中等的公司一种简单的日志ETL链路,Doris内部测试亿级日志场景一样性能非常好。
想要加入社区或对本文有任何疑问,可直接添加作者微信交流。
图:作者微信
我们是由一群数据从业人员,因为热爱凝聚在一起,以开源精神为基础,组成的PowerData数据之力社区。
可关注下方公众号后点击“加入我们”,与PowerData一起成长。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。