DataKit 日志采集器性能测试
环境和工具¶
- 操作系统:Ubuntu 20.04.2 LTS
- CPU:Intel(R) Core(TM) i5-7500 CPU @ 3.40GHz
- 内存:16GB Speed 2133 MT/s
- DataKit:1.1.8-rc1
- 日志文本(nginx access log):
172.17.0.1 - - [06/Jan/2017:16:16:37 +0000] "GET /datadoghq/company?test=var1%20Pl HTTP/1.1" 401 612 "http://www.perdu.com/" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36" "-"
- 日志数量:10w 行
- 使用 Pipeline:见后文
测试结果¶
测试条件 | 耗时 |
---|---|
不使用 Pipeline,纯日志文本处理(包括编码、多行和字段检测等) | 3 秒 63 |
使用完整版的 Pipeline(见附录一) | 43 秒 70 |
使用单一匹配的 Pipeline,与完整版相比舍弃多种匹配格式,例如 NGINX 错误日志,只针对 access.log(见附录二) | 16 秒 91 |
使用优化过的单一匹配 Pipeline,替换性能消耗多的 pattern(见附录三) | 4 秒 40 |
Attention
Pipeline 耗时期间,CPU 单核心满负载运行,使用率持续在 100% 左右,当 10w 条日志处理结束时 CPU 回落。测试期间内存消耗稳定,没有明显的使用率增加,耗时为 DataKit 程序计算,不同环境下可能会有偏差。
对比¶
使用 Fluentd 对同样 10w 行日志进行采集,CPU 使用率在 3 秒内从 43% 升至 77% 然后回落,可以预见此时已经处理结束。
因 Fluentd 存在 Meta-Data 缓存机制,分批次输出结果,所以无法确切计算究竟耗时多少。
Fluentd 的 Pipeline 匹配模式单一,没有进行同数据源多格式的 Pipeline(例如 nginx 只支持 access log 而不支持 error log)。
结论¶
Datakit 日志采集,在 Pipeline 单一匹配模式下,处理耗时和 Fluentd 相差 30% 左右。
但是如果使用完整版全量匹配 Pipeline,耗时剧增。
附录(Pipeline)¶
完整版/全量匹配 Pipeline¶
add_pattern("date2", "%{YEAR}[./]%{MONTHNUM}[./]%{MONTHDAY} %{TIME}")
# access log
grok(_, "%{IPORHOST:client_ip} %{NOTSPACE:http_ident} %{NOTSPACE:http_auth} \\[%{HTTPDATE:time}\\] \"%{DATA:http_method} %{GREEDYDATA:http_url} HTTP/%{NUMBER:http_version}\" %{INT:status_code} %{INT:bytes}")
# access log
add_pattern("access_common", "%{IPORHOST:client_ip} %{NOTSPACE:http_ident} %{NOTSPACE:http_auth} \\[%{HTTPDATE:time}\\] \"%{DATA:http_method} %{GREEDYDATA:http_url} HTTP/%{NUMBER:http_version}\" %{INT:status_code} %{INT:bytes}")
grok(_, '%{access_common} "%{NOTSPACE:referrer}" "%{GREEDYDATA:agent}')
user_agent(agent)
# error log
grok(_, "%{date2:time} \\[%{LOGLEVEL:status}\\] %{GREEDYDATA:msg}, client: %{IPORHOST:client_ip}, server: %{IPORHOST:server}, request: \"%{DATA:http_method} %{GREEDYDATA:http_url} HTTP/%{NUMBER:http_version}\", (upstream: \"%{GREEDYDATA:upstream}\", )?host: \"%{IPORHOST:ip_or_host}\"")
grok(_, "%{date2:time} \\[%{LOGLEVEL:status}\\] %{GREEDYDATA:msg}, client: %{IPORHOST:client_ip}, server: %{IPORHOST:server}, request: \"%{GREEDYDATA:http_method} %{GREEDYDATA:http_url} HTTP/%{NUMBER:http_version}\", host: \"%{IPORHOST:ip_or_host}\"")
grok(_,"%{date2:time} \\[%{LOGLEVEL:status}\\] %{GREEDYDATA:msg}")
group_in(status, ["warn", "notice"], "warning")
group_in(status, ["error", "crit", "alert", "emerg"], "error")
cast(status_code, "int")
cast(bytes, "int")
group_between(status_code, [200,299], "OK", status)
group_between(status_code, [300,399], "notice", status)
group_between(status_code, [400,499], "warning", status)
group_between(status_code, [500,599], "error", status)
nullif(http_ident, "-")
nullif(http_auth, "-")
nullif(upstream, "")
default_time(time)
单一匹配 Pipeline¶
# access log
grok(_, "%{IPORHOST:client_ip} %{NOTSPACE:http_ident} %{NOTSPACE:http_auth} \\[%{HTTPDATE:time}\\] \"%{DATA:http_method} %{GREEDYDATA:http_url} HTTP/%{NUMBER:http_version}\" %{INT:status_code} %{INT:bytes}")
cast(status_code, "int")
cast(bytes, "int")
default_time(time)
优化过的单一匹配 Pipeline¶
本例将性能消耗极大的 IPORHOST
改为 NOTSPACE
: