4. 日志采集架构:选对工具,事半功倍
日志采集是整个追踪链条的第一环。你想想看,如果连日志都收不上来,后面分析、溯源都无从谈起。我个人习惯把采集架构比作「水管系统」——源头要开得准,管道要通得快,中间还不能漏水。
我在项目中见过不少团队,一上来就上 Logstash,结果内存爆了、吞吐跟不上。其实吧,工具没有的好坏,关键看场景。今天我们就聊聊四种主流的采集方案。
4.1 Agent 采集:最朴素,也最稳
Agent 采集,说白了就是直接在业务服务器上装一个小程序,由它读日志文件、发到中心端。这种方式最直接,我早期做日志系统时就用这个。
常见的 Agent 实现方式:
- 自己写脚本:用 Python 或 Go 写个 tail -f,加个 HTTP/Syslog 发送。简单但容易丢数据。
- 使用开源 Agent:比如 Telegraf、Fluent Bit、rsyslog。稳定,但需要学习配置。
- 业务自带 SDK:Java 或 Python 里直接集成日志发送客户端。这种方式可控性最强,但改代码成本高。
避坑指南:我曾经在金融项目里直接用 Python 脚本做 Agent,结果日志量一大,脚本 CPU 跑满,业务进程都受影响。嗯,后来我才意识到——Agent 本身不能成为性能瓶颈。建议用 Go 或 C 写的 Agent,资源开销低很多。
4.2 Filebeat:轻量中的王者
Filebeat 是 Elastic 家的轻量采集器,我特别喜欢它。为什么?因为它占用的资源少,配置还简单。
一个典型的 Filebeat 配置长这样:
filebeat.inputs:
- type: log
enabled: true
paths:
- /var/log/app/*.log
multiline:
pattern: '^\d{4}-\d{2}-\d{2}'
negate: true
match: after
output.elasticsearch:
hosts: ["http://localhost:9200"]
username: "elastic"
password: "changeme"
| 特性 | 说明 |
|---|---|
| 资源占用 | 极低,10MB 内存即可运行 |
| 支持输入 | 文件、Syslog、TCP/UDP、容器 stdout |
| 支持输出 | Elasticsearch、Logstash、Kafka、Redis |
| 可靠性 | 内置 ACK 确认,保证至少一次送达 |
我在一个日处理量 10TB 的日志平台里,全部用 Filebeat 做边缘采集。因为它的注册表机制可以记录采集偏移量,就算进程重启也不会丢数据或者重复读。这个机制很重要,你想想看,在金融审计场景里,日志不能多也不能少。
4.3 Fluentd:灵活的路由之王
Fluentd 是 CNCF 毕业的项目,它是用 Ruby 写的(性能版叫 Fluent Bit,用 C 写)。我推荐用 Fluent Bit 做边缘采集,Fluentd 做中心聚合。
Fluentd 最大的特点是它的标签路由机制。你可以给不同来源的日志打上不同标签,然后分别处理:
<source>
@type tail
path /var/log/nginx/access.log
tag nginx.access
<parse>
@type nginx
</parse>
</source>
<source>
@type tail
path /var/log/nginx/error.log
tag nginx.error
</source>
<filter nginx.access>
@type record_transformer
<record>
hostname "#{Socket.gethostname}"
</record>
</filter>
<match nginx.*>
@type elasticsearch
host localhost
port 9200
logstash_format true
</match>
个人经验:使用 Fluentd 时,buffer_chunk_limit 和 buffer_queue_limit 这两个参数一定要调。我遇到过 Fluentd 集群因为默认缓冲区太小,导致日志积压,最终 OOM。建议小文件场景设 8MB,大流量设 256MB。
4.4 Logstash:功能强大,但有点重
Logstash 是 ELK 三件套之一,功能确实强大——Grok 解析、数据变换、丰富上下文……但它的缺点也很明显:重。
看看它默认启动占用——JVM 堆 1GB,跑起来 1.5GB 起步。我建议只在需要做复杂数据预处理时才用 Logstash。比如解压嵌套 JSON、做 GeoIP 地理解析、合并多行异常堆栈——这些活用 Filebeat 或 Fluent Bit 搞不定,就得交给 Logstash。
一个典型的 Logstash pipeline:
input {
beats {
port => 5044
}
}
filter {
grok {
match => { "message" => "%{COMBINEDAPACHELOG}" }
}
geoip {
source => "clientip"
target => "geoip"
}
mutate {
convert => { "response" => "integer" }
}
}
output {
elasticsearch {
hosts => ["http://elasticsearch:9200"]
index => "nginx-access-%{+YYYY.MM.dd}"
}
}
4.5 怎么选?一张表格说清楚
| 指标 | Filebeat | Fluentd/Fluent Bit | Logstash | 自定义 Agent |
|---|---|---|---|---|
| 资源占用 | 极低 | 低 | 高 | 取决于实现 |
| 数据预处理 | 弱 | 中等 | 强 | 自己写 |
| 输出丰富度 | 中等 | 丰富(100+插件) | 丰富(200+插件) | 自己写 |
| 部署复杂度 | 简单 | 中等 | 复杂 | 最复杂 |
| 适合场景 | 边缘轻量采集 | 多源、多目标 | 中心复杂处理 | 极致定制 |
我个人建议的选型原则:
- 边缘采集:用 Filebeat 或 Fluent Bit,轻量可靠。
- 中间聚合:用 Fluentd,路由灵活,插件多。
- 复杂处理:用 Logstash,但只让它干它擅长的活。
- 完全定制:自己写 Agent,但要做好断点续传、流量控制。
4.6 整体架构图
下面这张图展示了我常用的日志采集架构。它从日志源开始,经过采集、缓冲、解析,最终到存储和分析。
这个架构的核心设计理念是分层解耦。采集层只管收日志,不做复杂处理;缓冲层负责削峰填谷;解析层做格式统一和 Tokenization;最后才写存储。我在做大规模日志平台时,就是按这个思路搭建的,后期扩展非常容易。
4.7 我的避坑清单
这些年踩过的坑不少,一条条列出来,你以后遇到可以直接翻:
- 不要混用采集器:同一个日志文件同时被 Filebeat 和 Fluentd 读,会导致重复发送。我见过不止一次。
- 关注偏移量文件:Filebeat 的
registry文件、Fluentd 的pos_file。这些文件如果丢了,日志就会重读一遍。 - 设置限流:日志暴增时,采集器会拼命发。加一个
backpressure机制,避免压垮接收端。 - 预定义日志格式:应用日志最好输出为 JSON,这样采集端不用解析,直接发。我就是这样说服开发团队的。
- 监控采集器自身:采集器本身也要产生指标和日志。不然挂了都不知道。
日志采集架构这事,说白了就是「收得全、传得快、存得稳」。工具是手段,不是目的。花时间把架构搭稳了,后面做 Tokenization 凭据日志追踪才踏实。