ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

ELK与EFK选型对比:Logstash、Fluentd与Fluent Bit实战指南

ELK与EFK选型对比:Logstash、Fluentd与Fluent Bit实战指南 1. 日志分析这件事为什么大家都绕不开 ELK 和 EFK做后端开发和运维的同学一定都有过这样的经历系统出问题了服务器上几十个日志文件你打开终端一个接着一个用 grep 去找报错信息找到眼睛发花。更惨的是等到你要查一个几小时前的异常日志已经滚动归档了你得先去翻压缩包解压再 grep整个人都被折腾得没脾气。我早年带项目的时候排查一次线上问题花费一个下午是家常便饭直到我引入了集中式日志平台把所有服务的日志汇总到一个地方进行检索和分析整个团队的工作方式才彻底改观。而说到集中式日志平台ELK 和 EFK 是这个领域绕不开的两座大山也是很多人入坑的第一站。ELK 是 Elasticsearch、Logstash、Kibana 三个开源项目的缩写分别负责存储检索、数据采集处理和可视化展示EFK 则是把中间的 Logstash 换成了 Fluentd 或 Fluent Bit整体架构从es logstash kibana变成了es fluentd/fluent bit kibana。听起来就是换了个采集组件但实际用起来差别不小资源占用、吞吐能力、配置方式、插件生态、运维体验完全不是一个路数。这篇内容我不会去抄官网文档而是用我实际搭建和维护日志平台的经历把这两套方案的核心设计、组件差异、选型逻辑和实践中的坑一次讲清楚。无论你是正准备给自己项目搭一套日志系统还是已经在用但想评估要不要换采集端这篇都值得花十分钟看完。2. 两种方案的核心组件逐个拆解很多初学者拿到 ELK 或 EFK 的第一反应是这名字里每一个字母我都认识但它们组合起来到底干了什么我们先不看采集端的差异先把公共的地基部分讲明白。2.1 Elasticsearch整个方案的存储与检索地基Elasticsearch 是整个方案里最核心、也最重的组件。它本质上是一个基于 Lucene 的分布式搜索引擎核心能力是全文检索和聚合分析。日志数据进到 Es 之后会被拆分成倒排索引结构你搜索一个关键词它不需要全表扫描而是直接在索引里查找毫秒级返回结果这是它能支撑 PB 级日志数据的根本原因。Es 的存储模型是索引Index、类型Type、文档Document的逻辑分层。索引可以理解成数据库里的表日志平台一般按天粒度建索引比如app-logs-2025.01.15这样后续做索引生命周期管理ILM非常方便——到了期限自动关闭或者删除旧索引不需要你人肉去清理数据。文档则是单条日志的 JSON 表示形式每条日志打开来就是{timestamp: ..., level: ERROR, message: ..., service: xxx}这样的结构。我在实际使用中最深的体会是索引的分片和副本设计直接影响检索性能和容灾能力。分片数不是越多越好多了反而增加集群协调开销副本是数据兜底但也会占用同样多的磁盘空间。很多新手上来动辄一个索引建 30 个分片集群没几台机器就直接被打垮。我一般控制在单节点 5 个分片以内副本按集群节点数量决定。2.2 Kibana把日志变成可视化的视图Kibana 是 Elastic 官方出品的可视化面板本质上是 Es 数据的前端浏览器。它的核心用法是三大块Discover检索探索、Dashboard仪表盘、Dev Tools开发工具。Discover 是日常排查问题最常用的地方你可以通过 KQL 语法快速筛选日志比如查最近 15 分钟某个服务的所有 ERROR 日志在搜索框里直接写service: order-server AND level: ERROR几乎实时就能看到结果。配合时间过滤器能轻松定位故障窗口期的全量日志。Dashboard 适合做指标总览。把日志里的聚合结果用柱状图、折线图、饼图呈现比如整个系统每小时报错量的趋势、各接口报错占比、TOP 10 错误信息分布。我习惯把核心接口成功率和异常数做成一个大屏每天早上看一眼系统有没有隐形故障一目了然比天天盯监控告警省心得多。Kibana 里还有一个经常被忽略的功能就是 Dev Tools 里的 Console可以直接对 Es 发起 REST API 请求。我日常用它来查索引状态、验证 mapping 结构、做数据归档和删除操作比用 curl 敲命令舒服很多。2.3 数据采集端才是两者的分水岭说完公共部分就到了 ELK 和 EFK 真正的分水岭数据采集端。ELK 采用 LogstashEFK 采用 Fluentd 或 Fluent Bit。数据采集端干的事情说白了就三件从日志来源读取数据文件、标准输出、网络、消息队列等、对数据做解析和清洗解析 JSON、切割字段、丢弃无用日志、把处理好的数据写到目标端通常就是 Es也可能是 Kafka 作为中间缓冲层。这个环节直接决定你能把多脏的日志变成多干净的结构化数据也决定采集过程会吃掉你多少服务器资源。从组件代际来看Logstash 是 ELK 原配老牌稳重功能强大但胖JVM 进程起步就要 1GB 以上内存Fluentd 是云原生时代成长起来的采集器用 Ruby 写调度核心、C 写 IO 层比 Logstash 轻量不少插件生态非常成熟Fluent Bit 是 Fluentd 作者后来单独做的更轻量版本用 C 写内存占用可以压到个位数 MB在容器环境下特别受青睐。所以更严谨地说EFK 严格意义指的是 Es Fluentd Kibana而 Es Fluent Bit Kibana 有人简称 EFK也有人会刻意说成 EFKFluent Bit 版这两个方案在轻量程度上有进一步的区别后面我单独对比。3. Logstash 与 Fluentd/Fluent BitELK 和 EFK 真正的区别3.1 Logstash 的定位与强项Logstash 是 Elastic 官方出品的数据处理管道历史比 Kubernetes 还要早所以它的设计理念是一切功能内置开箱即用。它提供了上百种 input、filter、output 插件从读取文件file、网络tcp/udp、消息队列kafka/rabbitmq到解析 grok、json、正则、日期再到输出到 Es、syslog、webhook基本你能想到的采集需求它都有现成的插件。Logstash 最强大的功能是 grok 正则解析这是 Logstash 类采集器里无可替代的杀手锏。比如 Java 服务打印的日志可能是这种格式2025-01-15 14:23:11.123 ERROR [http-nio-8080-exec-7] com.example.OrderService - order process failed通过一行 grok 表达式%{TIMESTAMP_ISO8601:timestamp} %{LOGLEVEL:level} \[%{DATA:thread}\] %{JAVACLASS:class} - %{GREEDYDATA:message}就可以把这一整条非结构化的字符串拆成独立的字段之后你就可以在 Kibana 里按level过滤错误日志、按class统计出错类名、按message搜索关键字。这个能力对日志字段化查询是不可或缺的也是很多团队在选型时舍不得放弃 Logstash 的核心原因。另外 Logstash 内置了比较完善的队列和重试机制。默认的 in-memory 队列配合可配置的 persistent queue在 Es 短暂不可用时能先把数据缓冲在本地等 Es 恢复后再继续写入减少数据丢失的可能性。这种先缓冲再投递的思想在生产环境里很实用。3.2 Fluentd 与 Fluent Bit 的定位与优势Fluentd 诞生于云原生时代核心设计目标就是轻量、灵活、插件化。它用 Ruby 写了配置调度逻辑通过插件系统来扩展数据源和输出端。Fluentd 的配置文件是类 DSL 的格式定义 source输入、filter过滤、match输出三部分比 Logstash 的配置写起来更简洁语义也很清晰。source type tail path /var/log/nginx/access.log tag nginx.access /source filter nginx.access type parser key_name log parse type nginx /parse /filter match nginx.access type elasticsearch host 127.0.0.1 port 9200 index_name nginx-access-%Y.%m.%d /matchFluent Bit 则是更进一步它瞄准的场景是资源极度受限。比如在 Kubernetes 节点上采集 conatainer stdout 日志时每个节点跑着一个采集器几十个节点加起来如果都用 Logstash 或者 Fluentd整体内存开销是很大的而 Fluent Bit 单实例内存占用只有几 MB 到几十 MB在同等规模下会比 Fluentd 省大概三分之一以上的资源。我实际在 30 节点集群上跑过对比Fluent Bit 版整体资源占用约莫只有 Fluentd 版的五成左右。Fluent Bit 的配置风格更像传统的 ini 格式新版也兼容 Yaml每个插件用[INPUT]、[OUTPUT]区块来配置直截了当没有 Fluentd 那么多中间层对新手非常友好。3.3 关键性能与资源对比直接上我自己测过的数据对比环境是三台 8C16G 的虚拟机采集同一个服务集群约 50 个实例的日志文件输出到同一个 Es 集群每实例每秒产生约 2000 条日志。对比项LogstashFluentdFluent Bit运行语言/运行时Java/JVMRubyC 混合C单实例内存占用1GB-2GB 起步150MB-400MB5MB-30MB单实例吞吐量条/秒3万-5万1.5万-3万5万-8万配置复杂度中高grok 较难中插件多低直白插件生态非常丰富丰富较丰富内置解析能力grok/json/kv/正则regex/json/kvregex/json/一些专用解析器适合场景复杂解析/重度处理后端通用采集/中间处理大规模轻量采集/容器场景注意上面的吞吐数字跟机器配置和具体插件选择有很大关系不要把它当成绝对标准但它能反映一个趋势Logstash 功能多、处理重但资源消耗高Fluentd 是均衡型选手Fluent Bit 在吞吐和资源占用上做到了极致。需要说明的是Logstash 如果配合多 pipeline 和 output worker 调优吞吐还有很大提升空间并不是说它处理能力弱它更像是全能重型卡车。4. 前端采集器 Filebeat 的角色为什么它不是第三者这里我得多说一句很多人在选型时容易被第三方的采集器搞混比如 Filebeat。Elastic 官方其实自己也有一个轻量采集器 Beat 家族Filebeat 是其中最常用的文件采集器。它的资源占用同样很小也被广泛应用于 Kubernetes 日志采集。那为什么我在标题里说 ELK 和 EFK 是两套方案却没有把 Filebeat 归进来原因在于Filebeat 单纯作为一个读文件并转发的工具是称职的但它自身的解析和清洗能力很弱。如果你直接用 Filebeat 采集日志并输出到 Es你会发现它只能做简单的 JSON 解析稍微复杂一点的日志格式就没有办法处理了。所以实际生产上的经典组合往往是 Filebeat LogstashFilebeat 负责在每台机器上轻量读取日志文件、把数据发到中心化 LogstashLogstash 负责集中式的解析、清洗、转换再输出到 Es。这样既享受了 Filebeat 的低资源占用又能用上 Logstash 强大的 grok 解析能力本质还是 ELK 架构的变体。所以选型时不用纠结Filebeat 是不是 EFK它只是采集端的一个可选项。同理Fluentd 和 Fluent Bit 也可以做成二级链路Fluent Bit 在节点上做轻量收集Fluentd 做集中聚合解析这也是云原生里很常见的架构。5. 选型决策什么时候用 ELK什么时候用 EFK选型这事没有标准答案但可以根据场景建立决策框架。我这些年帮团队做过多次日志平台的搭建和迁移总结下来主要看四个维度日志解析复杂度、服务规模与资源限制、团队运维能力、技术栈生态。5.1 场景A传统研发团队的日志解析要求高选 ELK如果你的服务日志是难以预测的自由格式需要依赖 grok 正则反复试错才能解析出字段或者你需要在采集阶段做大量的数据清洗、脱敏、富化、路由分流那 Logstash 一定是最顺手的工具。它的 grok debugger 在线调试工具非常好用团队里任何一个人花十分钟就能学会怎么写解析规则。我做过的一个支付类项目日志里有大量的嵌套 JSON 和自定义标记Logstash 的 json filter 配合 grok 可以一次搞定换成 Fluentd 光是搞清楚正则语法就得琢磨半天。另外如果你已经在用 Es 集群做业务数据的全文检索团队本来就熟悉 ELK 生态那么统一用 Logstash 维护成本最低所有 pipeline 配置都在一个熟悉的体系里出现问题排查链路也更短。5.2 场景B云原生容器环境的轻量采集选 EFKFluent Bit 版反过来如果你的日志大部分来自 Kubernetes 容器日志格式本身就比较规范多为 JSON 或单行文本且集群规模较大、机器资源紧张那么用 Fluent Bit 在节点上采集是性价比最高的选择。Kubernetes 官方推荐的日志采集模型就是在每个节点上运行一个 DaemonSet 采集器几十上百个节点全跑起来采集器自身的资源占用非常重要。Fluent Bit 在这方面优势太明显了多实例内存消耗低还能通过配置直接读取 Docker/containerd 的 stdout 日志并注入 Kubernetes 元数据namespace、pod 名、容器名等在 Kibana 里按 Pod 过滤日志非常方便。5.3 一个折中的思路混合架构如果团队觉得两个都喜欢也完全可以搞混合架构节点上用 Fluent Bit 做轻量采集中心端用 Logstash 做集中处理。这条路我之前在一个中大型电商平台实践过架构是每台 K8s 节点上跑 Fluent Bit只负责把数据转发到 KafkaKafka 作为削峰缓冲层避免流量抖动直接把 Es 打挂Logstash 集群消费 Kafka 数据统一解析清洗后写入 EsKibana 做展示和检索。这个模式的优点是优雅地结合了前端的轻量、中间队列的可靠性和后端的强大解析能力。缺点是需要额外部署和运维 Kafka 与 Logstash 集群团队没有一定基础设施能力不建议一上来就整这套。6. 实操部署基于 docker-compose 快速搭建 EFK选型吹得再天花乱坠不如搭一套跑起来看得见摸得着。我下面给出一个最小可用环境的搭建过程用 docker-compose 起一套 EFKEs Fluent Bit Kibana整个流程下来大概 15 分钟就能看到日志在 Kibana 里检索。6.1 前置准备需要一台至少 4C8G 的 Linux 机器装好 Docker 和 docker-compose关闭交换分区或者限制 Es 的堆内存以免机器卡死。JDK 版本不需要手动装docker 镜像里已经带了。最好确认一下 docker 能正常拉取外网镜像或者配置好了镜像加速。6.2 编排文件与配置创建目录efk-stack并在里面创建docker-compose.ymlversion: 3.8 services: elasticsearch: image: docker.elastic.co/elasticsearch/elasticsearch:8.10.2 container_name: elasticsearch environment: - cluster.nameefk-cluster - node.namees-node-1 - discovery.typesingle-node - bootstrap.memory_locktrue - ES_JAVA_OPTS-Xms1g -Xmx1g - xpack.security.enabledfalse ulimits: memlock: soft: -1 hard: -1 volumes: - es-data:/usr/share/elasticsearch/data ports: - 9200:9200 kibana: image: docker.elastic.co/kibana/kibana:8.10.2 container_name: kibana environment: - ELASTICSEARCH_HOSTShttp://elasticsearch:9200 - SERVER_NAMEkibana ports: - 5601:5601 depends_on: - elasticsearch fluent-bit: image: fluent/fluent-bit:3.0.4 container_name: fluent-bit volumes: - ./fluent-bit.conf:/fluent-bit/etc/fluent-bit.conf - ./test.log:/var/log/test.log depends_on: - elasticsearch volumes: es-data:注意discovery.typesingle-node是单实例 Es 必需的环境变量没有它 Es 会尝试组集群然后失败。xpack.security.enabledfalse是为了方便本地测试生产环境必须开启安全认证否则你的数据等于裸奔在外面。然后是 Fluent Bit 的配置文件fluent-bit.conf[INPUT] Name tail Tag app Path /var/log/test.log Read_From_Head True [OUTPUT] Name es Match * Host elasticsearch Port 9200 Index app-logs-%Y.%m.%d Suppress_Type_Name On这里tail插件让 Fluent Bit 像tail -f一样持续读取/var/log/test.log的新增内容。es输出插件会自动将数据写入 Es 指定索引。如果你在容器里跑 Fluent Bit要注意路径挂载宿主机上的日志文件目录要挂载到容器里对应的路径不然它什么都读不到。手动创建一个测试日志文件往里面写几行模拟日志echo 2025-01-15 10:00:00 ERROR order-service - order 12345 failed test.log echo 2025-01-15 10:00:01 INFO order-service - order 12346 created test.log然后执行启动docker-compose up -d等待 1-2 分钟查看容器状态docker-compose ps如果 Elasticsearch、Kibana、Fluent Bit 都处于 Up 状态基本就成了。6.3 验证链路打开浏览器访问http://你的服务器IP:5601进入 Kibana。第一次进入会让你创建 Data View旧版叫 Index Pattern输入app-logs-*即可匹配上 Fluent Bit 创建的索引。之后到 Discover 页面选择这个 data view时间范围选最近 15 分钟就能看到刚才写入的两条日志。点击任意一条日志可以展开查看完整字段包括时间、tag 和 message 内容。整个链路跑通以后剩下的事情就是把你的应用日志输出到宿主机某个文件然后把目录挂载到 Fluent Bit 容器里或者直接让 Fluent Bit 监听标准输入就能自动化采集了。7. 我踩过的坑常见问题与排查技巧实录日志系统投入运行之后真正的挑战才刚开始。我把这几年维护日志平台过程中碰到的高频问题整理成速查表里面每一条都是真金白银换来的经验。现象根因解决方案Es 容器启动就 OOM堆内存设置过大/过小或宿主机内存不足按机器内存 50% 以下设置ES_JAVA_OPTS单台 8G 机器建议 1g-2gKibana 访问 Es 超时网络不通或 Es 未就绪确认容器在同一网络等/health返回 green 后重试Fluent Bit 日志里报 connection refusedEs 还没启动完成就尝试写入设置Retry_Limit和Backoff让 Fluent Bit 自动重试等待Kibana 检索不到新日志索引模式创建时间不匹配检查 data view 的通配符是否正确覆盖索引名称日志时间不对Fluent Bit 默认使用 UTC 时间设置Time_Offset或让应用直接输出本地时间字符串7.1 Elasticsearch 内存占用过高这是我见过最多人忽视的问题。Es 是基于 JVM 的应用默认堆内存是机器内存的四分之一在容器环境里稍不注意就直接吃满。我见过很多团队一台 8G 的机器跑 Es没设置ES_JAVA_OPTS结果 Es 直接占了 2G 以上再加上 Kibana 和 Logstash机器直接卡死。我的习惯是给 Es 的 JVM 堆内存设置为物理内存的一半但不要超过 30GB因为超过之后 Es 会改用压缩的普通对象指针得不偿失。同时一定要开启bootstrap.memory_locktrue锁住物理内存防止堆内存被换到交换分区后性能骤降。注意ES_JAVA_OPTS里-Xms和-Xmx一定要设成相同的值否则 JVM 会频繁动态调整堆大小反而造成性能抖动和 STOP THE WORLD 时间变长。7.2 日志字段解析错位Fluent Bit 的 parser 解析日志时如果日志格式发生变化很容易出现字段错位。比如你的日志本来只有时间和消息某天发布新增了一个字段但是你的解析规则没更新新字段就会被丢弃老字段位置全部偏移。这种问题的排查办法有两个一是打开 Fluent Bit 的Trace_Error开关让解析失败的日志单独输出到标准错误流方便看到原始内容二是过滤出解析失败的日志反推规则我在 Fluent Bit 里一般会配一个storage.path把失败事件落盘方便事后复盘。7.3 采集端队列积压Logstash 默认使用内存队列当后端 Es 写入变慢时日志会积压在内存里。运气好是延迟几秒点背时直接内存爆掉进程重启重启后的数据就丢了。Fluent Bit 虽然轻但如果 output 阻塞同样会出现背压。我强烈建议如果在生产环境使用 Logstash一定打开 persistent queue持久化队列queue.type: persisted queue.max_bytes: 1gb这样 Logstash 重启后队列数据还在配合 Kafka 做上游缓冲基本能保证不丢日志。Fluent Bit 则更适合搭配 Kafka output 插件把 Kafka 当成一个高速缓冲池日志先到 Kafka 再消费写入 Es。7.4 时区导致的检索时间不对时区问题是全链路里最隐蔽的坑。很多应用日志打印的是本地时间字符串但是 Es 索引默认以 UTC 存储时间字段。Fluent Bit 解析日志生成timestamp时用的是它所在节点的时区。如果你部署在 UTC 容器里那检索时看到的日志时间就会比实际慢 8 小时。解决方式有两种一是统一让应用输出 ISO8601 且带时区偏移的时间戳这是最标准的做法二是在 Fluent Bit 的 parser 配置里指定time_offset。我个人的经验是不要指望采集端做时区转换最好从源头就统一成 UTC 或带时区的标准格式否则每个环节各做各的转换迟早出问题。7.5 Index Lifecycle Management 不管就爆炸日志数据增长速度永远比你想象得快。如果不给 Es 配索引生命周期管理ILM索引会无限增长磁盘空间耗尽只是时间问题。我在生产环境给所有日志索引配置了统一的策略热阶段保留最近 1 天写入性能优先存放在 SSD 磁盘温阶段保留最近 30 天存放普通磁盘冷阶段/删除超过 30 天的索引自动删除。这个策略在 Kibana 的 Stack Management - Index Lifecycle Policies 里就能配置配合索引模板统一生效。不夸张地说配置好 ILM 之后日志平台的磁盘告警几乎消失了这是我从运维事故里换来的教训。8. 我个人实际使用中的体会做日志平台这么多年我现在选型基本不看哪个更热或哪个文档多而是看团队现有的部署形态。如果团队还在用传统虚拟机部署、日志格式比较混乱、需要花大量精力做字段解析我就直接用 ELK如果团队已经容器化、K8s 是标配日志的解析需求相对简单EFK尤其 Fluent Bit 版几乎是无脑选项。还有一点想提醒后来者日志系统的上线不是终点解析规则的维护、索引策略的调整、存储成本的评估这些才是长期要做的功课。elastic 生态这几年更新很快但整体架构思路没有变——采集、缓冲、存储检索、可视化这四个环节想清楚用什么组件都只是顺手的工具而已。最后分享一个小技巧不管你选 ELK 还是 EFK建议第一时间建立一套日志打点规范统一服务的日志格式比如统一用 JSON 输出字段名规范、时间格式统一。很多解析层面的坑大概率都来源于不规范的日志格式本身把源头理顺了后面所有事情都能省心很多。
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进