日志采集架构:从源头说起
日志采集,说白了就是解决「日志怎么到平台」的问题。我刚开始做风控平台时,觉得这步最简单——不就是把日志文件读出来发走吗?结果第一个线上事故就给我上了一课:采集器挂了,风控模型跑了一周假数据,损失惨重。
所以今天咱们聊聊日志采集的几种主流方案,以及怎么搭一套高可用的采集架构。
常见日志采集方案
目前业界用得最多的三款工具:Filebeat、Logstash、Fluentd。我按自己的使用经验,一个个说。
Filebeat:轻量级采集器
Filebeat 是 Elastic 家的产品,主打轻量。它只做一件事:读日志文件,发出去。不做复杂处理,不占太多资源。
我在项目中遇到过这种情况:业务服务器上跑着 Java 应用,内存本来就紧张。如果用 Logstash 采集,内存直接飙到 1GB+,业务方投诉。换成 Filebeat,内存占用不到 50MB,问题解决。
核心特点:
- Go 语言编写,二进制文件只有十几 MB
- 支持断点续传(这个很重要,后面会讲)
- 内置 Elasticsearch、Logstash、Kafka 输出
- 不支持复杂数据处理
Filebeat 的配置很简单,举个例子:
filebeat.inputs:
- type: log
paths:
- /var/log/nginx/access.log
fields:
app: nginx
env: prod
output.elasticsearch:
hosts: ["http://es-cluster:9200"]
index: "nginx-access-%{+yyyy.MM.dd}"
嗯,这里要注意:Filebeat 默认的采集速度是 5 秒一次。如果日志量特别大,可以调小 scan_frequency 参数,但别低于 1 秒,否则 CPU 会飙高。
Logstash:全能型处理器
Logstash 是 ELK 里的「L」,功能最全。它不仅能采集,还能做数据清洗、格式转换、字段提取。说白了,它是个管道,日志从一头进去,经过各种插件处理,从另一头出来。
我曾经用 Logstash 处理过风控日志里的 IP 地址。原始日志里 IP 是字符串,我需要把它转成整数,方便做地理定位。Logstash 的 mutate 插件一行搞定:
filter {
mutate {
convert => { "client_ip" => "integer" }
}
}
但 Logstash 有个硬伤:吃内存。默认 JVM 堆内存 1GB,处理复杂规则时还会更高。所以我的建议是:Logstash 适合做集中式处理,不适合部署在业务服务器上。
| 特性 | Filebeat | Logstash |
|---|---|---|
| 资源占用 | 低(~50MB) | 高(~1GB+) |
| 数据处理 | 不支持 | 强大(200+ 插件) |
| 适用场景 | 边缘采集 | 集中处理 |
Fluentd:数据路由专家
Fluentd 是 Treasure Data 开源的项目,在日本和国内都很流行。它的核心优势是数据路由——你可以把不同来源的日志,按规则分发到不同目的地。
举个例子,风控平台里,交易日志要发到 Kafka,系统日志要发到 Elasticsearch,审计日志要存到 S3。用 Fluentd 的 match 规则,配置起来很清晰:
<match transaction.*>
@type kafka
brokers kafka-cluster:9092
topic transactions
</match>
<match system.*>
@type elasticsearch
host es-cluster
port 9200
</match>
Fluentd 的插件生态也很丰富,但配置语法有点怪(用 XML 风格),刚上手时容易写错。我个人习惯用 Filebeat + Logstash 组合,但如果你团队熟悉 Ruby,Fluentd 是个好选择。
采集架构设计原则
做了这么多年风控,我总结了几条采集架构的设计原则。你想想看,日志采集就像自来水管道——源头脏、管道长、用户多。设计不好,要么堵,要么漏。
原则一:解耦采集与处理
采集器只负责读日志、发日志。数据处理交给下游。为什么?因为采集器挂了,至少日志还在磁盘上;处理节点挂了,采集器还能缓存数据。
我曾经见过一个团队,用 Logstash 既采集又处理,结果 Logstash 处理规则写错了,直接把日志全丢弃了。等发现时,已经丢了 3 小时的数据。嗯,从那以后我再也不敢把采集和处理混在一起。
原则二:引入缓冲层
缓冲层是日志采集的「保险丝」。常见的缓冲层有 Kafka、Redis、RabbitMQ。我个人最推荐 Kafka,原因有三:
- 高吞吐:每秒几十万条没问题
- 持久化:数据不会丢
- 多消费者:一个日志可以被多个系统消费
没有缓冲层的架构,就像没有蓄水池的自来水厂——下游一停,上游就得停。
原则三:保证至少一次投递
日志采集最怕丢数据。Filebeat 和 Fluentd 都支持「至少一次」语义。原理很简单:采集器记录自己读到哪一行了(offset),如果发送失败,下次重试时从 offset 继续读。
但要注意:「至少一次」不等于「精确一次」。如果下游重复消费,需要业务层做去重。风控场景里,重复日志可能导致重复计算,所以我会在日志里加一个唯一 ID,下游用 ID 去重。
高可用采集方案
单机采集肯定不行。服务器宕机、网络抖动、磁盘写满,任何一个问题都能让采集中断。下面是我在风控平台里用的高可用方案。
方案一:多采集器 + 负载均衡
每台业务服务器部署两个 Filebeat 实例。一个主采集,一个备用。主采集挂了,备用自动接管。配合 Nginx 或 HAProxy 做负载均衡,把日志均匀分发到下游。
配置上,Filebeat 支持 output 多节点:
output.logstash:
hosts: ["logstash-1:5044", "logstash-2:5044"]
loadbalance: true
这样即使一个 Logstash 节点挂了,Filebeat 会自动切换到另一个。
方案二:Kafka 做缓冲层
这是最稳妥的方案。架构是这样的:
业务服务器 → Filebeat → Kafka → Logstash → Elasticsearch
Kafka 在这里起两个作用:
- 削峰填谷:业务高峰期日志量暴增,Kafka 能扛住
- 故障隔离:Logstash 挂了,Filebeat 照常写 Kafka;Kafka 挂了,Filebeat 本地缓存
Filebeat 支持 Kafka 输出,配置也很简单:
output.kafka:
hosts: ["kafka-1:9092", "kafka-2:9092"]
topic: "app-logs"
partition.round_robin:
reachable_only: true
方案三:本地缓存 + 重试机制
如果网络不稳定,或者下游服务经常挂,可以在采集器本地做缓存。Filebeat 默认使用 registry 文件记录 offset,即使进程重启,也能从断点续传。
我建议把缓存目录放在独立磁盘上,避免和系统日志抢 I/O。另外,缓存文件要定期清理,否则磁盘会满。
避坑指南:我曾经遇到过 Filebeat 缓存文件损坏,导致日志重复采集。后来我加了一个监控:每天检查 registry 文件大小,超过 100MB 就报警。另外,Filebeat 的 close_inactive 参数别设太大,否则文件句柄会一直占用。
架构图:一张图看懂采集链路
下面这张 SVG 图,展示了我最常用的采集架构。你一看就明白:
这张图里,核心思路是:采集端轻量、中间层缓冲、处理端集中。每个环节都有冗余,任何一个节点挂了,整个链路不会断。
小提示:如果你刚开始搭建采集架构,别追求一步到位。先从 Filebeat + Elasticsearch 开始,等日志量上来了,再逐步加入 Kafka 和 Logstash。我见过太多团队一开始就上全套 ELK,结果运维成本比业务开发还高。
好了,日志采集架构就聊到这儿。下一节咱们会深入日志格式规范——毕竟,采集上来的日志如果格式乱七八糟,后面处理起来会非常痛苦。