前阵子有朋友在群里问:现在做日志采集,到底该直接用ELK,还是加上Filebeat和Kafka?他说团队日志量算不上爆炸,一天也就几十GB,但近期业务波动一上来,Logstash的CPU经常飙到90%以上,Kibana的图表偶尔还会出现断档。这个问题问得很典型,因为ELK(Elasticsearch+Logstash+Kibana)作为日志领域的老牌组合,曾经是很多团队的第一套日志方案;可等规模稍微起来一点,它的短板就暴露得很明显。而ELFKK(Elasticsearch+Logstash+Kibana+Filebeat+Kafka)这套加了Filebeat和Kafka的升级版本,正好是把传统方案里最吃力的两个环节拆出来解耦。这篇文章我就以自己上手改造的经验为线索,把这两套架构从组件职责、数据流设计、可靠性、成本几个维度彻底拆一遍,顺带整理一些实操配置和排坑记录,给正在纠结架构成熟的团队一份能直接参考的对比笔记。
1. 两个架构的“家底”盘点
1.1 ELK传统架构:Logstash一肩挑的三件套
ELK最早的形态就是Elasticsearch、Logstash、Kibana三件套,数据链路是:应用/服务器日志 -> Logstash采集 -> Elasticsearch存储索引 -> Kibana可视化。这套方案在那几年确实火,原因很直接:组件少、概念简单、部署起来快。Logstash负责所有脏活累活:从文件、网络、数据库里采集数据,然后做过滤、清洗、格式化,最后再写入Elasticsearch。一个Logstash实例既能当采集器又能当管道处理器,对小体量团队来说,省掉了很多中间环节。
但问题恰恰出在“一肩挑”上。Logstash底层是JVM,默认堆内存几个GB起步,启动就要占用不少资源;它又内置了大量插件和过滤规则,每次数据进来都要经过完整的pipeline处理。如果采集端直接让Logstash去tail服务器上的日志文件,那么每增加一台业务机器,就要评估Logstash能不能撑住,尤其在高吞吐场景下,Logstash的内存和CPU很容易被拖垮,而一旦Logstash宕机,采集链路就等于彻底断掉,日志直接丢。用我自己的话说:Logstash是一个能干活的壮汉,但你不太可能让壮汉去每层楼跑腿收垃圾,不然垃圾没收拾完,壮汉先累倒了。
1.2 ELFKK架构:加入Filebeat和Kafka到底改了什么
ELFKK在传统ELK基础上加了两个角色:Filebeat负责轻量采集和传输,Kafka负责消息缓冲和削峰填谷。改造后数据流变成:服务器日志 -> Filebeat采集 -> Kafka队列 -> Logstash消费清洗 -> Elasticsearch存储索引 -> Kibana展示。
这中间最关键的改动就是把原来Logstash的“采集”职责完全剥离开。Filebeat是一个用Go写的轻量级采集器,默认内存占用只有几十MB,部署在每台业务服务器上几乎感觉不到存在,但它能做日志文件的实时追踪、多行日志合并、断点续传这类事情,而且做得比Logstash更专注、更稳。Kafka则像一个巨大的蓄水池,帮助整个管道在面对流量洪峰时能顺利缓冲。业务日志突然涨了10倍没关系,Logstash按照自己的节奏从Kafka里慢慢消费就行,不会因为瞬间压力过大直接垮掉。
1.3 到底适合谁:先算清楚自己的量级再选架构
从实际落地角度讲,这两套架构并没有绝对的好坏,关键看规模和场景。如果你只是几台服务器、几套测试环境,日志量每天几个GB到十几个GB,那直接用ELK就够,多引入Kafka反而增加运维成本。但如果是几十台服务器以上、日志量日增长在几十GB甚至百GB级别,或者业务有明显的“凌晨跑批”和“活动大促”这类高峰流量,那么Kafka的缓冲能力几乎会成为刚需。
我自己是经历过“ELK能跑”到“ELK不敢重启”这个阶段的。有一段时间每天晚上业务批量任务跑起来,Logstash的队列就会不断积压,Elasticsearch的写入QPS被打满,Kibana上的日志延迟越来越高。后来加上Filebeat和Kafka之后,这些问题基本都消停了,原因就是链路里的每个角色都只干一件事,而且各干各的,互不拖累。
2. 架构设计思路完全不同的底层逻辑
2.1 Logstash的高成本为什么成了“原罪”
先说一个很多新手忽略的问题:Logstash在工作时到底干了什么。它的pipeline由input、filter、output三段组成,采集、解析、清洗、写入一体。这个设计在早期确实降低了使用门槛,但随着日志量增大,这套流程很容易出现“木桶效应”。举个例子:你的日志格式多种多样,有Nginx访问日志、Java异常堆栈、业务埋点JSON,Logstash里的filter要写一堆grok、mutate、json插件去做解析,解析本身要消耗CPU;而同时它还承担着从远程文件或网络端口读取日志的I/O任务,内存里要缓冲等待处理的数据,垃圾回收(GC)又要抢占资源。
更重要的是,Logstash的采集模式是“推”模式,它主动去读文件、监听端口,一旦Logstash慢下来,上游的日志文件会被持续占用;一旦Logstash崩溃重启,文件读到了哪里、哪些日志还没发出去,恢复逻辑并不算特别完善。这个架构在数据完整性上天然有短板。我见过有团队用ELK做生产日志采集,Logstash一挂,重启之后发现丢失了最后几分钟的日志,因为文件读取的位置标记没有及时更新。这其实是ELK直连采集方式难以避免的问题,不是调参能完全解决的。
2.2 Kafka缓冲层如何真正解决削峰填谷
Kafka在这里的核心贡献不是“更快”,而是“更稳”。它把原本Logstash直连数据源的模式彻底解耦成生产-消费模式。Filebeat作为生产者把日志源源不断写入Kafka,Logstash作为消费者按自己的处理能力从Kafka拉取数据。Kafka的Broker是集群模式,数据以分区(Partition)形式持久化在磁盘上,消费者可以根据自己的消费能力决定拉取速率,Kafka不会因为消费者处理不过来而拒绝接收数据。
这带来的直接好处就是:无论业务端日志如何暴涨,Filebeat都只需要把数据交给Kafka就行,它不需要关心下游Logstash是否跟得上。而Logstash也可以从容地按照一个比较平滑的吞吐量持续消费,再写入Elasticsearch。等于整个链路的压力峰值从Logstash环节被转移到了Kafka,而Kafka恰恰是所有组件里最能扛高吞吐的那个。我实际测试过,原来Logstash直连源端的峰值吞吐大概在每秒几万条时会明显抖动;改成从Kafka消费后,只要把Topic分区数规划好,Logstash的消费速率能做到非常平稳。
2.3 为什么最终选择Filebeat而不是其他采集器
选Filebeat作为轻量采集端,最核心的考量是资源占用低、体量小、够稳定。Filebeat默认只需要很小的内存,CPU占用也远低于Logstash,可以在每台业务服务器上常驻而不影响业务性能。它有一些非常好用的设计:比如读取文件时会记录offset(偏移量),Kafka又叫做消费位点,这样即使采集器重启也能从断点处继续读,不会漏掉日志;它还支持多行消息合并,遇到Java异常栈这类跨多行的日志,可以配置multiline规则把它们拼成一条完整的日志记录。
很多人可能会问,为什么不用Logstash的file input,或者干脆自己写个脚本?原因是Filebeat的成熟度已经很高了,它能处理日志文件轮转、备份文件导致的重复读、以及关闭文件句柄这类边界场景。这些问题自己写脚本很容易踩坑,而Filebeat都内置解决好了。我在实际迁移过程中,最直观的感受就是部署Filebeat就是解压、改配置、启动,没有任何编译和依赖安装的负担,和Logstash的Java环境相比完全不是一个量级。
2.4 数据流的本质变化:从同步直连到异步管道
对比两套架构的数据流设计,最本质的差别在于“同步直连”和“异步管道”。ELK是Logstash从日志文件拉到数据后,经过处理再写入Elasticsearch,这中间链路是串行的;一旦Logstash出问题,整条链路马上阻塞。扩展的时候只能靠加Logstash节点,但没有缓冲层,加了节点又得考虑负载均衡和重复读问题。ELFKK把Filebeat、Kafka、Logstash分成三段,各自伸缩互不影响。Filebeat不够就加Filebeat,Logstash消费不过来就加Logstash消费组,Kafka分区数决定并行度天花板。
这套异步管道的设计思路,说白了就是借鉴了消息中间件在传统后端架构里做异步解耦的套路。和你在业务系统里引入MQ削峰、异步处理是一样的道理,只不过这里“消息”变成了日志记录。想通了这一点,两套架构的优劣其实就非常清晰了:ELK适合小规模,ELFKK适合需要可靠性和扩展性的场景。
3. 核心差异细节对比与关键参数选择
3.1 资源占用与性能表现的实测对比
我拿一个7台业务服务器的中型测试环境做过一组对比实验。ELK方案是在一台独立的4核8G机器上跑Logstash,每天日志量大约50GB;ELFKK方案是用每台业务服务器上的Filebeat采集,然后写入一套3节点的Kafka,再让Logstash从Kafka消费。两者最终都写入同一个Elasticsearch集群。
实验下来最直观的数据是:ELK方案下,Logstash的JVM堆内存长期在4GB左右徘徊,CPU平均使用率60%以上,高峰期经常到90%以上;改用ELFKK后,Logstash只消费Kafka数据,内存稳定在2GB,CPU平均降到30%左右,Filebeat在每台业务服务器上的CPU占用率几乎都在1%到3%之间波动,内存始终在50MB上下。吞吐方面,加了Kafka之后整体链路反而更稳定,日志从产生到可搜索的延迟从原来的峰值几分钟降到了秒级以内,因为Logstash不用花时间在读文件上,可以把CPU资源全部分配给解析和输出。
这里要提一个容易忽略的细节:ELK方案里硬盘I/O也是一个瓶颈。Logstash如果直接从文件读取,磁盘读和网络写入同时发生,容易造成磁盘争抢;而Filebeat只做轻量读取,Kafka写入又是顺序追加,两者在各自主机上都不会形成太大压力。如果团队用云服务器,磁盘性能本身就有上限,这个差异在压力测试中更容易被放大。
3.2 数据可靠性:丢失、积压、重复消费如何取舍
日志场景下数据可靠性主要指不丢数据、不乱数据、尽量不重复。ELK直连架构下,Logstash从文件读取数据时如果宕机,重启后虽然可以从offset恢复,但需要依赖文件系统里记录的读取位置,如果系统不是优雅退出,可能会出现漏读或者重读。再加上Logstash本身没有持久化队列,默认在内存里缓冲,一旦进程被杀,内存里排队的数据就全没了。
ELFKK对这个问题做了两个层面的缓解。首先是Filebeat自带持久化状态,它会把每个文件读到的offset记录到本地registry文件,机器重启后会自动从上次位置继续读,这点比Logstash更可靠。其次是Kafka,数据一旦写入Kafka就落盘保存,并且有副本机制,Logstash即使挂了,数据还躺在Kafka里,等Logstash恢复后继续消费就行;想多保留几天数据,只需要调整Kafka的retention配置。
但引入Kafka也带来了一个最经典的新问题:重复消费。Logstash处理完一批数据并提交offset,但如果它在提交之前宕机,Kafka会认为这批数据还没消费完,重启后重新拉取,这就导致同一批日志重复写入Elasticsearch。这个问题的解决思路不是完全避免,而是控制影响面。常见办法一是让Elasticsearch在索引设计上使用唯一ID,文档写入时按ID去重;二是让Logstash的管道是幂等性的,保证重复执行不会造成逻辑错误。我在实际使用中,因为日志场景基本是追加写、不对单条日志做修改,所以重复消费对最终搜索影响不大,计数器类统计需要自己考虑幂等处理。
3.3 扩展性与运维成本到底谁更划算
从扩展性角度看,ELFKK的架构优势非常明显。业务新增服务器时只需要在上面部署一个Filebeat,改一下Kafka地址配置,然后重启即可;Logstash端不需要做任何变更,Kafka的新分区会自动让新的数据进入消费流程。而ELK方案每新增一台服务器,都得评估现有Logstash能不能承载,很可能需要再部署一个Logstash节点,还要处理负载均衡和多实例下的重复读问题。
但从运维成本看,ELFKK引入的额外组件可不少。Kafka是一个分布式系统,需要考虑Broker数量、分区数、副本因子、磁盘容量、消息保留时间等一堆参数,还要维护Controller的正常切换。如果团队没有专门维护消息队列的经验,初期上手会有一点陡峭。好在Kafka的运维成熟度很高,常规的监控指标比如消息堆积、消费延迟都有现成的工具可以看,网上教程一大把。如果让我给一个建议:小规模集群可以用单节点Kafka先跑起来,注重稳定性再升级到多节点,不必一上来就搞很多Broker。
另外,Elasticsearch本身也是比较吃运维的资源。无论ELK还是ELFKK,最后都要落到Elasticsearch的索引规划、分片设置和生命周期管理上。很多团队把Elasticsearch调优当成一个专题,这不算架构本身的差异。
3.4 成本账:一台Logstash和三节点Kafka怎么比
很多人一听增加Kafka集群就觉得成本高不少。其实细算下来未必。ELK方案里高负载的Logstash往往需要一台4核8G甚至更高的机器;而Kafka节点虽然要多买几台,但规格不用太高,2核4G的机器就能跑得很稳,多副本可以分散到已有机器上。我常用的一个配置是三台2核4G的Kafka,副本因子设为2,日常吞吐几MB/s完全没压力。
如果对比总持有成本,成本差异主要体现在机器数量上,但换来的是Logstash不用因为资源紧张频繁扩容,Elasticsearch的写入负载也平滑了很多。有一点容易被忽略:Kafka的数据是可以重复消费的,某些实时计算或离线分析任务也能复用同一份日志数据,这种数据复用的收益是ELK直连架构无法提供的。所以从长期看,如果日志数据不只是给Kibana用,还要喂给实时计算或数仓,那Kafka这个组件几乎是必选项。
4. 实操接入:从ELK平滑迁移到ELFKK的关键步骤
4.1 Filebeat核心配置详解:不是改几行就完事
Filebeat的配置核心在filebeat.yml,我看过不少团队的配置文件,最容易出问题的就是input类型和fields的使用场景搞混。我常用的一个采集Nginx访问日志的配置如下:
filebeat.inputs: - type: filestream id: nginx-access enabled: true paths: - /var/log/nginx/access.log parsers: - ndjson: target: "" fields: log_type: nginx-access service: web-prod fields_under_root: false output.kafka: hosts: ["10.0.0.11:9092", "10.0.0.12:9092", "10.0.0.13:9092"] topic: "app-log" partition.hash: reachable_only: true required_acks: 1 compression: gzip max_message_bytes: 1048576这里面有几个容易踩的坑。paths指到日志文件路径,如果业务日志是按日期自动生成的新文件,建议使用带通配符的路径,比如/var/log/myapp/*.log;type用filestream是新版推荐的做法,老版本用log类型,两者在状态管理上有些差异,建议新项目直接用filestream。fields可以给日志打上标签,后面Logstash和Kibana可以依据这个字段区分日志来源,很重要。output.kafka里的topic可以按照日志类型分开,后续消费端可以针对不同类型的Topic走不同的解析规则。partition.hash表示按哈希方式选择分区,避免同一业务日志被分散到太多分区导致乱序。required_acks设成1即可保证数据写入leader,同时性能损失小;如果不要求极致性能,设成all也可以,只是会多一层网络开销。
4.2 Kafka的Topic和分区数应该怎么规划
Topic和分区数的规划是个值得认真思考的事情。日志场景下,分区数实际上代表了Logstash消费者并行度的上限。如果只有一个分区,那无论起多少个Logstash实例,同一时刻只有其中一个能真正消费这个分区的数据,并行度就上不去。所以我一般建议按业务日志类型建Topic,比如app-log、nginx-access、db-slowlog,每个Topic的分区数根据预估吞吐量来定。简单的经验值是:目标吞吐量除以单个消费者实际消费能力。假设单个Logstash每秒能消费1万条日志,业务高峰期每秒产生5万条日志,那么至少需要5个分区才够并行消费;考虑到单点故障和消费端抖动,一般建议留一定余量,设置8个分区或者更多。
分区数也不是越多越好。分区太多一方面会加重Kafka的元数据管理压力,另一方面可能导致小文件过多,影响清理效率。日志场景常见做法是6到12个分区起步,后续如果吞吐量上来了再增加分区,这也是允许的,只要Key设计合理,不会因为动态扩分区导致数据严重乱序。创建Topic的命令比较简单:
kafka-topics.sh --create --topic app-log \ --partitions 8 --replication-factor 2 \ --bootstrap-server 10.0.0.11:9092,10.0.0.12:9092,10.0.0.13:9092注意一下replication-factor,这是副本数。如果你只有一台Kafka,那只能设1,这没问题,但别指望这台机器挂了日志还能不丢。想要高可用,至少3台机器、副本因子设2,前提是机器数量够。
4.3 Logstash从Kafka消费时的Pipeline配置要点
Logstash的input改为Kafka之后,配置方式和原来的file、beats模式完全不同。下面是一个从Kafka消费、解析、再写入Elasticsearch的基础配置:
input { kafka { bootstrap_servers => "10.0.0.11:9092,10.0.0.12:9092,10.0.0.13:9092" topics => ["app-log", "nginx-access"] group_id => "logstash-es" consumer_threads => 6 codec => "json" auto_offset_reset => "latest" } } filter { if [log_type] == "nginx-access" { grok { match => { "message" => "%{IPORHOST:client_ip} - - \[%{HTTPDATE:timestamp}\] \"%{WORD:method} %{URIPATHPARAM:request}\" %{INT:status} %{INT:bytes}" } } } } output { elasticsearch { hosts => ["10.0.0.21:9200", "10.0.0.22:9200"] index => "%{[@metadata][beat]}-%{+YYYY.MM.dd}" manage_template => false } }这里最关键的两个参数是consumer_threads和auto_offset_reset。consumer_threads控制单个Logstash进程里消费Kafka的线程数,通常可以设置为分区数的整数倍,但是也不要大于分区数太多,否则有些线程可能闲着。auto_offset_reset决定当消费者没有记录消费位点时的行为:earliest会从最早的消息开始消费,适合数据完整重建场景;latest只消费新消息,适合搜索场景,因为搜索通常不需要历史日志。实际生产环境我一般设为latest,想象成“只关心新日志”,这样重启Logstash后不会因为消费老日志把Elasticsearch打爆——这个问题很容易踩,第一次用Kafka时我设成earliest,结果一启动Logstash就疯狂往Elasticsearch灌旧数据,集群直接报警。
filter段里可以按log_type字段分流做不同解析,这一点在从ELK迁移时特别省事。因为写日志的地方可能已经在日志内容里自带了结构化字段,比如用JSON格式输出的业务日志,codec设为json后Logstash会自动解析成字段,就不用再写一堆grok规则了。迁移时可以先只增加Kafka消费,保留原有filter和output逻辑,收益最明显的就是input替换掉了原来读文件那一段。
4.4 迁移过程中的几个关键避坑操作
我在迁移实际环境时总结了几条经验,可以给准备动手的团队做个参考。第一条是先建Kafka、再切Filebeat,不要同时把Filebeat和Kafka一起上线,一旦出问题不好定位到底哪个环节坏了。第二条是刚开始迁移时,让Filebeat同时输出到Kafka和原有Logstash,做一个并行验证阶段,可以对比两边收到的日志条数,确认Kafka链路没丢数据之后再切流量。第三条是注意Elasticsearch的索引模板,因为不同采集端写入的索引名称可能不同,如果原来索引有自定义mapping,需要提前把模板准备好,避免新链路把字段类型搞乱。
另外一个容易被忽略的问题是Kafka消息体大小。日志单条很大(比如包含完整请求体或异常栈)时,Kafka默认的max.message.bytes可能会有问题。需要在Broker端调大message.max.bytes,同时Filebeat端max_message_bytes也要相应调整,Logstash的kafka input侧也要设置合适的fetch_max_bytes等参数。否则客户端写入时会直接报错“Message size too large”,而且报错信息很隐蔽,不是一眼能看出来的。我在测试环境就遇到过,Nginx日志本来很小没事,接入业务埋点日志后突然大量写失败,查了半天才发现是消息体超过1MB默认限制。
5. 常见问题与排查技巧实录
5.1 Kafka消费延迟高,如何一步步定位
日志链路中“消息堆积”可能是最常遇到的问题了。表现就是Kibana里看到的日志时间比实际时间晚了几分钟甚至更多,此时Kafka里应该积压了大量未消费的消息。排查思路一般是从Kafka的消费状态入手。用Kafka自带的命令行工具能直接看出每个消费者组落后的消息数:
kafka-consumer-groups.sh --bootstrap-server 10.0.0.11:9092 \ --group logstash-es --describe这个命令会输出每个Topic分区的当前消费位点(current-offset)和最新位点(log-end-offset),两者相减就是Lag(积压量)。如果Lag长期不为0且持续变大,说明消费速度跟不上生产速度。这时候先看Logstash的CPU和堆内存,如果CPU已经打满,优先调大consumer_threads或增加Logstash实例;如果CPU还有余量但消费慢,可能是Elasticsearch写入端成了瓶颈,需要看Elasticsearch的索引写入QPS和拒绝数。
另外注意,consumer_threads只是单进程内的线程数,如果开了多个Logstash实例消费同一个group_id,需要确保Topic分区数不小于消费者总数,否则会有消费者空闲,Lag还是下不去。这是我排过低级坑的一个场景:部署了两台Logstash,但Topic只有两个分区,第二台几乎一直闲着,因为分区不够分,最终消费能力只等于单台。解决方式就是把Topic分区数扩到足够大,然后两个消费端就都能分到分区了。
5.2 关于重复消费,把影响控制在合理范围
Kafka引入之后,“能重复消费吗”这个问题经常被问到。答案是能,而且分布式系统下完全避免几乎不可能。Logstash从Kafka拉取一批数据,处理完还没提交offset就宕机,Kafka就会在消费者恢复后重新推送这一批数据,于是同一批日志可能被写两次Elasticsearch。解决思路我之前提过,一是接受它在日志追加场景下无伤大雅,因为日志本身是“一次生成、多次查询”,重复写几行对搜索结果没有实质影响;二是在更严格场景下做去重。
去重的实现方式其实不复杂。如果你的日志有唯一的请求ID或者事件ID,可以在Elasticsearch索引文档里使用这个ID作为文档ID,这样即便同一日志重复写入,Elasticsearch也会用相同的ID覆盖,从源头上避免多条重复文档。Logstash的elasticsearch output支持document_id字段,用它的其中一个字段做ID即可:
output { elasticsearch { hosts => ["10.0.0.21:9200"] index => "app-log-%{+YYYY.MM.dd}" document_id => "%{request_id}" } }要注意的是,使用document_id会增加Elasticsearch的写路径负担,而且业务日志如果没有天然唯一ID,这个方案就不适用。日志搜索场景一般优先级不高,不用为了细节非要去重不可。
5.3 生产消费命令的一些误区
在Kafka的学习过程中,有不少开发者在测试环境用命令行直接消费消息验证数据,却对“命令会不会一直运行”感到困惑。实际上kafka-console-consumer.sh默认启动后就会保持阻塞状态,持续等待并打印新消息,这其实是正常现象,因为它是一个持续运行的消费者。而kafka-console-producer.sh启动后,如果不输入内容并回车,也不会报错,就是一直等着。知道这个背景对排障很有用,我见过同事误以为命令卡死了,直接Ctrl+C中断,搞得后面的验证全乱套。
生产环境里我更推荐用kafkacat这类客户端工具来验证Kafka中是否有数据,因为它支持在指定超时时间后退出,命令也简洁很多。不过这个工具名字现在改成了kcat,直接用包管理器装就行。
5.4 一个容易被忽略的Elasticsearch管控问题
Elasticsearch的License机制也经常被问到。新版本默认提供了基础授权(Basic License),包含安全管理、快照和恢复、跨集群复制等核心能力,对绝大多数日志存储和搜索场景是够用的。但是某些高级功能,比如机器学习、自定义告警等,需要付费订阅。如果你在升级Elasticsearch版本后发现某个功能提示License不允许,不要一开始就想着“破解”或者绕过,先确认一下自己的使用场景是否真的需要这个能力,很多时候换个思路就能解决。
有些团队会选OpenSearch作为Elasticsearch的替代方案,它基于Apache 2.0协议,没有License限制问题,但要注意它的API兼容性。日志场景下如果你只用基础查询、聚合、Kibana可视化,迁移到OpenSearch通常问题不大;但如果你的业务代码里用了大量Elasticsearch特有API,就需要逐一验证兼容性。这个选择要结合团队实际情况评估,没有所谓的最佳答案。
5.5 实操心得:日志平台建设里最值得先做的一件事
做日志平台这些年,我最深的体会是:不要一上来就纠结选ELK还是ELFKK,先把手头日志的格式规范和来源梳理清楚。很多团队最后排查困难,不是因为架构选错了,而是日志源头乱:有的服务打的是纯文本,有的打的JSON,有的时间字段格式五花八门。Logstash和Kafka都只是管道,管道的清洗能力再强,也架不住上游数据质量太差。
所以在改造到ELFKK之前,我强烈建议先花一两个迭代把日志规范定下来。能做到每条日志都有统一的时间戳格式、日志级别、服务名、请求ID,后面无论用ELK还是ELFKK都会省非常多事。我自己当时就是因为日志格式太乱,在从ELK迁移到ELFKK时,Filter规则几乎重写了一遍,如果一开始规范一点,迁移成本至少能少一半。
另外还有一个性价比很高的实践:在Filebeat端就把日志类型和来源用fields字段打上标签。这样Logstash处理时可以通过条件分支做不同解析,Kibana里也可以直接按来源过滤。这个习惯一养成,后续不管是排障还是做数据分析,都能少走很多弯路。
这套架构的取舍没有标准答案,拉长到3年周期看,加了Kafka的ELFKK在多业务线、日志量持续增长的环境下显然更有生命力。但如果你只在几台服务器上做简单的日志检索,硬上Kafka确实有点杀鸡用牛刀。说到底,日志链路的设计还是要跟着业务量级和查询需求走,工具只是手段,能稳定地拿到干净、完整、可检索的日志,才是真正的目标。