日志采集架构:ELK/EFK架构详解、Filebeat与Logstash的区别、Kafka在日志链路中的作用
聊到日志采集,很多团队上来就搭一套ELK。嗯,这个方向没错,但你真的理解每一层在干什么吗?我见过不少项目,日志量一上来,整个链路直接崩掉。说白了,架构设计没想清楚。
今天咱们就把日志采集链路拆开揉碎,从ELK/EFK的架构差异,到Filebeat和Logstash怎么选,再到Kafka为什么成了日志链路的标配。我会结合自己踩过的坑,给你讲明白。
一、ELK vs EFK:核心差异在哪?
先看经典ELK:Elasticsearch + Logstash + Kibana。这套组合用了很多年,成熟稳定。但后来大家发现Logstash吃内存太狠了,尤其是日志量大的时候,动不动就OOM。
于是EFK出现了:Elasticsearch + Filebeat + Kibana。把Logstash换成了更轻量的Filebeat。你想想看,Filebeat是用Go写的,资源占用比Logstash小一个量级。
核心区别一句话:Logstash是重量级采集+处理,Filebeat是轻量级采集+转发。
我个人习惯这样选型:
- 日志量小于100GB/天:直接用ELK,Logstash扛得住,功能也全
- 日志量100GB-1TB/天:EFK + 轻量处理,Filebeat采集,Logstash只做过滤
- 日志量超过1TB/天:必须上Kafka,Filebeat采集 -> Kafka缓冲 -> Logstash/ES消费
我在项目中遇到过一家电商公司,双十一日志量暴涨10倍,Logstash直接挂了。后来改成Filebeat + Kafka,稳如老狗。这个教训让我记住了:架构设计一定要考虑峰值。
二、Filebeat与Logstash:到底怎么选?
很多新手会问:Filebeat和Logstash不是都能采集日志吗?为什么搞两个?
其实它们定位完全不同。我画个对比你就明白了:
| 特性 | Filebeat | Logstash |
|---|---|---|
| 语言 | Go | Ruby/JRuby |
| 资源占用 | 极低(10-50MB内存) | 较高(256MB-2GB内存) |
| 处理能力 | 仅采集和简单转发 | 强大的过滤、转换、富化 |
| 插件生态 | 有限 | 200+插件 |
| 适用场景 | 边缘节点、容器环境 | 中心化处理、复杂管道 |
你看,Filebeat就像快递员,只管把包裹从A送到B。Logstash像分拣中心,能拆包、检查、重新打包。
我的建议:Filebeat部署在每台机器上采集日志,Logstash集中部署做数据清洗。这样既轻量又灵活。
我曾经在一个K8s集群里,每个Pod都挂了个Logstash sidecar,结果内存直接爆了。后来全换成Filebeat DaemonSet,资源占用降了80%。
三、Kafka在日志链路中的作用
为什么日志链路要加Kafka?说白了就三个字:解耦合。
你想想看,如果没有Kafka,Filebeat直接往Elasticsearch写日志。一旦ES挂了或者慢查询,Filebeat就得阻塞等待。日志积压,磁盘写满,整个系统跟着遭殃。
Kafka在中间起到了几个关键作用:
- 削峰填谷:日志洪峰来了,Kafka先扛住,下游慢慢消费
- 数据缓冲:ES挂了也不怕,Kafka保留数据,恢复后继续消费
- 多路分发:一份日志可以同时给ES、Spark、Flink消费
- 回溯重放:出问题时,可以从Kafka重新消费历史日志
典型架构链路:
应用日志 -> Filebeat -> Kafka -> Logstash(过滤) -> Elasticsearch -> Kibana
我在一个金融项目中,日志链路必须保证99.99%不丢。Filebeat采集后写入Kafka,Kafka配置了3副本+acks=all。即使ES集群挂了三天,Kafka里还躺着几TB日志,恢复后一条没丢。
注意:Kafka不是银弹。如果你的日志量很小(每天几GB),加Kafka反而增加了运维复杂度。我建议日均日志量超过500GB再考虑引入Kafka。
四、实战:一个完整的日志采集配置
给你看一个我常用的Filebeat配置,采集Nginx日志到Kafka:
# filebeat.yml
filebeat.inputs:
- type: log
enabled: true
paths:
- /var/log/nginx/access.log
fields:
log_type: nginx_access
env: production
output.kafka:
hosts: ["kafka1:9092", "kafka2:9092", "kafka3:9092"]
topic: "nginx-logs"
partition.round_robin:
reachable_only: true
required_acks: 1
compression: gzip
max_message_bytes: 1000000
然后Logstash从Kafka消费,做字段解析:
# logstash.conf
input {
kafka {
bootstrap_servers => "kafka1:9092,kafka2:9092"
topics => ["nginx-logs"]
codec => "json"
consumer_threads => 4
}
}
filter {
grok {
match => { "message" => "%{COMBINEDAPACHELOG}" }
}
date {
match => ["timestamp", "dd/MMM/yyyy:HH:mm:ss Z"]
}
}
output {
elasticsearch {
hosts => ["http://es-cluster:9200"]
index => "nginx-logs-%{+YYYY.MM.dd}"
}
}
这套配置我用了两年多,日均处理200GB日志,从未出过问题。关键点就两个:Filebeat压缩传输、Kafka合理分区。
五、避坑指南
最后分享几个我踩过的坑:
- Filebeat多行日志处理:Java异常栈是多行的,记得配置
multiline,否则一条异常被拆成几十条 - Kafka分区数:分区数不是越多越好。我建议分区数 = 消费线程数 × 2,太多反而增加元数据开销
- Logstash内存配置:默认1GB不够,我一般给4GB。用
-Xms4g -Xmx4g设置 - ES索引生命周期:日志索引一定要配ILM,否则磁盘撑爆了都不知道
我曾经因为没配ILM,ES集群磁盘使用率飙到95%,整个集群变成只读模式。那叫一个惨,恢复了两天才把数据导出来。
好了,日志采集架构就聊到这。下一章咱们深入讲讲Elasticsearch的索引优化和查询调优,到时候见。