第2章:日志采集技术选型 — Filebeat vs Fluentd vs Logstash

日志采集是整个监控体系的起点。起点选错了,后面再折腾也白搭。

我见过不少团队,一上来就上 Logstash,结果内存吃紧、CPU 飙高,最后不得不推倒重来。也见过用 Filebeat 跑得很欢,但遇到复杂解析需求时,又得再套一层 Fluentd。说白了,没有银弹,只有最合适的组合。

2.1 三大采集器横向对比

先看一张对比表,心里有个底:

特性 Filebeat Fluentd Logstash
开发语言 Go Ruby + C JRuby (JVM)
资源占用 极低(~10MB) 低(~50MB) 高(~500MB+)
吞吐量 高(10万+ 事件/秒) 中高(5-10万 事件/秒) 中(受JVM限制)
插件生态 有限(主要面向ES) 丰富(1000+ 插件) 丰富(200+ 插件)
数据缓冲 内置内存/磁盘缓冲 内置缓冲 + 插件扩展 依赖队列 + 持久化
部署复杂度 极简(单二进制) 简单(gem安装) 复杂(依赖JVM)
适用场景 轻量采集 + 转发 多源采集 + 路由 复杂处理 + 清洗

我个人习惯这样选型:

  • Filebeat:纯采集转发,不做复杂处理。适合边缘节点、K8s Sidecar 模式。
  • Fluentd:需要多源接入、标签路由、中间处理。适合中大型集群。
  • Logstash:需要深度解析、数据清洗、格式转换。适合中心化处理层。

核心原则:采集层尽量轻,处理层尽量重。别把脏活累活都堆在采集端。

2.2 采集器部署架构

部署架构决定了你的运维成本和扩展能力。我见过三种主流模式:

2.2.1 直连模式(小规模)

每个节点部署 Filebeat,直接发送到 Elasticsearch 或 Kafka。简单粗暴,适合几十台机器的场景。

# 架构示意
App Log → Filebeat → Elasticsearch

嗯,这里要注意:一旦节点数超过 100,ES 的写入压力会陡增。我曾经踩过这个坑,Filebeat 默认的 bulk 大小是 1MB,并发一高,ES 直接拒绝连接。

2.2.2 缓冲模式(中规模)

引入 Kafka 或 Redis 作为缓冲层。采集器只管收,消费者慢慢处理。

# 架构示意
App Log → Filebeat → Kafka → Logstash → Elasticsearch

为什么加 Kafka?说白了,就是为了解耦。采集端和消费端可以独立扩缩容。我在一个日处理 10TB 日志的项目里,就是靠 Kafka 扛住了流量洪峰。

小技巧:Filebeat 的 output.kafka 支持压缩,建议开启 gzip 压缩,能省 60% 的网络带宽。

2.2.3 多层聚合模式(大规模)

边缘节点用 Filebeat 采集,汇聚到 Fluentd 做标签路由,再转发到 Logstash 做深度处理。

# 架构示意
Node1: Filebeat → Fluentd (聚合层) → Kafka
Node2: Filebeat → Fluentd (聚合层) → Kafka
Kafka → Logstash → Elasticsearch

这种架构的好处是:每一层职责单一。Filebeat 只管采集,Fluentd 只管路由,Logstash 只管处理。出了问题,定位也快。

2.3 日志源接入方式

日志源五花八门,但接入方式就那么几种。我重点讲三个最常见的:

2.3.1 文件接入

最传统的方式。Filebeat 的 input.log 模块,Fluentd 的 in_tail 插件,Logstash 的 file 输入插件,都能搞定。

# Filebeat 配置示例
filebeat.inputs:
- type: log
  enabled: true
  paths:
    - /var/log/app/*.log
  multiline.pattern: '^\d{4}-\d{2}-\d{2}'
  multiline.negate: true
  multiline.match: after

你想想看,多行日志(比如 Java 异常栈)怎么处理?上面这个配置就是答案:按时间戳开头合并多行。

避坑指南:我曾经遇到过 Filebeat 读取日志文件时,因为日志轮转(logrotate)导致文件句柄丢失。解决办法是开启 close_inactive: 5mclean_removed: true,让 Filebeat 自动清理过期文件句柄。

2.3.2 TCP/UDP 接入

适合接收远程日志,比如网络设备、第三方系统。Fluentd 的 in_tcp 和 Logstash 的 tcp 输入插件是主力。

# Fluentd TCP 接入配置
<source>
  @type tcp
  port 5140
  bind 0.0.0.0
  tag syslog
  <parse>
    @type syslog
  </parse>
</source>

注意:TCP 接入要小心连接数。我曾经在生产环境开了一个 TCP 端口,结果被几百台设备同时连接,Fluentd 直接 OOM。后来加了 client_max_connections 限制才稳住。

2.3.3 Kubernetes 容器日志接入

K8s 环境下的日志采集,是现在最主流的需求。我推荐两种方式:

  • DaemonSet 模式:每个节点部署一个采集器,读取宿主机上的容器日志文件。Filebeat 和 Fluentd 都支持。
  • Sidecar 模式:每个 Pod 里挂一个采集容器,专门负责日志转发。适合需要独立配置的场景。
# Fluentd DaemonSet 配置(关键部分)
apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: fluentd
spec:
  template:
    spec:
      containers:
      - name: fluentd
        image: fluent/fluentd:v1.16
        volumeMounts:
        - name: varlog
          mountPath: /var/log
        - name: dockercontainers
          mountPath: /var/lib/docker/containers
          readOnly: true
      volumes:
      - name: varlog
        hostPath:
          path: /var/log
      - name: dockercontainers
        hostPath:
          path: /var/lib/docker/containers

我个人更倾向 DaemonSet 模式。为什么?因为 Sidecar 模式会浪费资源——每个 Pod 多一个容器,1000 个 Pod 就多 1000 个采集进程。而 DaemonSet 只跟节点数挂钩,成本可控。

总结一下

  • 小规模、轻量需求 → Filebeat
  • 多源、路由需求 → Fluentd
  • 复杂处理、清洗需求 → Logstash
  • K8s 环境 → DaemonSet + Filebeat/Fluentd

好了,日志采集这块就聊到这儿。下一章我们聊聊日志传输的可靠性保障——说白了,就是怎么保证日志不丢、不重、不乱序。到时候见。