Logstash 数据采集与管道架构
如果你管过几套 ELK,应该会同意:Logstash 是整个体系里最容易被低估但也最容易出事的环节。数据进不来、处理慢、OOM 崩掉,八成都是管道设计没想清楚。这一章我把管道模型、插件使用、多路并行、性能调优和 OOM 排查串起来讲,每一点都配上我自己的实战经验。
事件处理管道模型:Input / Filter / Output
Logstash 的管道模型说白了就是三条带的流水线:Input → Filter → Output。每条数据从 Input 进入,经过 Filter 加工,最后从 Output 送走。理解了这个模型,你才能知道配置怎么写、性能瓶颈在哪。
| 阶段 | 职责 | 我常用的插件 |
|---|---|---|
| Input | 从源头拉数据,支持文件、TCP、Kafka、Beats 等 | file, beats, kafka, tcp |
| Filter | 解析、转换、增强、脱敏 | grok, mutate, json, date, geoip |
| Output | 写到下游(ES、Kafka、文件、邮件等) | elasticsearch, kafka, stdout |
你想想看,每一个事件都要完整走完这三个阶段,如果其中任何一步慢了,整条管道就会堵住。我在项目中见过很多人把 filter 写得特别重,grok 匹配几十个正则,结果吞吐量直接掉到 100 条/秒。所以我的建议是:能不做的 filter 就不做,能提前过滤的就扔到 Input 侧。
插件系统:拧螺丝的思路
Logstash 有 200+ 官方插件,社区还有一堆。你不用全记住,只需要掌握最常用的那 10 来个。插件本质上就是一个个 Ruby 类,按照 Input / Filter / Output / Codec 分类。每个插件都有自己的一套配置参数。
举个例子,grok 是最强大的 filter,但也是最吃 CPU 的。我曾经在一个金融项目里用了 20 多个 grok 模式去解析不同格式的应用日志,结果 CPU 飙到 90%。后来我把模式拆成多个 if 分支,提前用 type 分流,每个事件只走一个分支,CPU 降到 30%。
多管道并行采集
单一管道在处理多数据源时容易互相干扰——比如慢的 filter 拖慢所有输入。Logstash 从 6.x 开始支持多管道(multiple pipelines)。你可以在 pipelines.yml 里定义多个独立管道,每个管道有自己的一套 Input → Filter → Output,完全隔离。
# pipelines.yml 示例
- pipeline.id: app-log
pipeline.workers: 8
path.config: "/etc/logstash/conf.d/app-log.conf"
- pipeline.id: mysql-slow
pipeline.workers: 4
path.config: "/etc/logstash/conf.d/mysql-slow.conf"
- pipeline.id: metric
pipeline.workers: 2
path.config: "/etc/logstash/conf.d/metric.conf"
多管道的核心好处是“故障隔离”。如果 App 管道 clog 了,MySQL 管道依然能正常写数据。但注意:每个管道会独自占用内存和线程,总资源是固定的,别开太多管道把 JVM 撑爆。
性能调优参数
调优就是找平衡点。下面这几个参数是必须关注的,我每次上线前都会过一遍。
| 参数 | 默认值 | 说明与我的经验 |
|---|---|---|
pipeline.workers | CPU 核心数 | 建议不超过 CPU 核数的 2 倍,太大会因上下文切换变慢 |
pipeline.batch.size | 125 | 批量处理事件数。IO 密集时调大(如 500-1000),但注意内存 |
pipeline.batch.delay | 50 | 等待批量的时间(毫秒)。适当调小能降低延迟 |
queue.type | memory | 生产环境建议用 persisted,防止意外重启丢数据 |
heap size | 1GB | JVM 堆大小。我通常设为物理内存的 50%(不超过 32GB) |
为什么建议 persisted 队列?因为内存队列一旦进程挂掉,正在排队的事件全丢。我曾经在压测时人为 kill 掉 Logstash 进程,重启后数据对不上,排查了好久才发现是队列丢失。调成 persisted 后,重启能正常恢复。
Logstash OOM 问题排查
说到这个我就想起一个真实的教训。有一次客户反馈日志中心突然没有新数据了,我一看 Logstash 进程已经 OOM killed。当时版本是 7.0,配置了多个管道,堆给了 4GB。
排查步骤:
- 看 JVM 监控——发现堆内存使用量不断攀升,GC 频率越来越密集,最后 Full GC 失败。
- 抓 heap dump——用
jmap在崩溃前保存了 dump,分析发现是jsonfilter 解析一个超大 JSON 字段(某个业务日志里嵌了 50MB+ 的 Base64 图片数据)导致对象膨胀。 - 定位根因——那个字段本不该出现在日志中,是上游开发写入了调试信息。我们用
prunefilter 提前去掉那个字段,并把pipeline.batch.size从 500 降回 125,OOM 再没出现。
codec 截断,或者在 filter 里用 mutate 的 replace 替换为空。我曾经在另一个项目中也见过因为 gzip 解码后字符串太长导致的 OOM。
本章核心框架:Logstash 管道架构
下面这张图概括了多管道并行、每个管道内的三阶段模型、以及队列与 worker 的关系。你写配置、排问题的时候,脑子里一直有这个图就对了。