4. 日志采集架构:选对工具,事半功倍

日志采集是整个追踪链条的第一环。你想想看,如果连日志都收不上来,后面分析、溯源都无从谈起。我个人习惯把采集架构比作「水管系统」——源头要开得准,管道要通得快,中间还不能漏水。

我在项目中见过不少团队,一上来就上 Logstash,结果内存爆了、吞吐跟不上。其实吧,工具没有的好坏,关键看场景。今天我们就聊聊四种主流的采集方案。

4.1 Agent 采集:最朴素,也最稳

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}"
  }
}
注意:Logstash 的 Grok 模式如果写不对,会导致解析失败。我在高流量环境中被坑过一次——写错正则导致 CPU 直接飙到 800%。先在小数据量上验证 Grok,再上生产。

4.5 怎么选?一张表格说清楚

指标 Filebeat Fluentd/Fluent Bit Logstash 自定义 Agent
资源占用 极低 低 高 取决于实现
数据预处理 弱 中等 强 自己写
输出丰富度 中等 丰富(100+插件) 丰富(200+插件) 自己写
部署复杂度 简单 中等 复杂 最复杂
适合场景 边缘轻量采集 多源、多目标 中心复杂处理 极致定制

我个人建议的选型原则:

  • 边缘采集:用 Filebeat 或 Fluent Bit,轻量可靠。
  • 中间聚合:用 Fluentd,路由灵活,插件多。
  • 复杂处理:用 Logstash,但只让它干它擅长的活。
  • 完全定制:自己写 Agent,但要做好断点续传、流量控制。

4.6 整体架构图

下面这张图展示了我常用的日志采集架构。它从日志源开始,经过采集、缓冲、解析,最终到存储和分析。

Tokenization 凭据日志采集架构 日志源 应用 / 系统 / 容器 采集层 Filebeat / Fluent Bit / Agent 断点续传 + 偏移量管理 缓冲 / 队列 Kafka / Redis / 内存 削峰填谷 解析 / 过滤 Logstash / Fluentd Grok / 正则 / 结构化 数据富化 GeoIP / 上下文 TokenID 绑定 存储 / 输出 Elasticsearch / ClickHouse 关键设计要点 采集层做 Tokenization 缓冲层防雪崩

这个架构的核心设计理念是分层解耦。采集层只管收日志,不做复杂处理;缓冲层负责削峰填谷;解析层做格式统一和 Tokenization;最后才写存储。我在做大规模日志平台时,就是按这个思路搭建的,后期扩展非常容易。

4.7 我的避坑清单

这些年踩过的坑不少,一条条列出来,你以后遇到可以直接翻:

  1. 不要混用采集器:同一个日志文件同时被 Filebeat 和 Fluentd 读,会导致重复发送。我见过不止一次。
  2. 关注偏移量文件:Filebeat 的 registry 文件、Fluentd 的 pos_file。这些文件如果丢了,日志就会重读一遍。
  3. 设置限流:日志暴增时,采集器会拼命发。加一个 backpressure 机制,避免压垮接收端。
  4. 预定义日志格式:应用日志最好输出为 JSON,这样采集端不用解析,直接发。我就是这样说服开发团队的。
  5. 监控采集器自身:采集器本身也要产生指标和日志。不然挂了都不知道。

日志采集架构这事,说白了就是「收得全、传得快、存得稳」。工具是手段,不是目的。花时间把架构搭稳了,后面做 Tokenization 凭据日志追踪才踏实。