上一篇讲完了性能调优的系统方法。这一篇进入演进对比阶段,把 Logstash、Beats 和 Elasticsearch Ingest Pipeline 三者并排放,回答一个工程决策问题:同样是把数据搬进 ES,三种路径在哪里分叉,分叉的依据是什么。

核心问题:轻量采集用 Beats,简单解析下沉到 Ingest Pipeline,复杂转换才留给 Logstash——这条分工逻辑背后的资源、能力和可靠性代价是什么?

三者的定位

Elastic Stack 的数据接入层有三个层次,各自定位不同:

1
2
3
4
5
6
7
8
9
10
11
数据源

├─▶ [Beats] Go 语言,轻量级进程,单一职责,低资源
│ │
│ ├─▶ [ES Ingest Pipeline] 运行在 ES 节点内,无独立进程,简单变换
│ │
│ └─▶ [Logstash] JVM 进程,200+ 插件,复杂转换,PQ 可靠性
│ │
│ └─▶ Elasticsearch

└─▶ Elasticsearch(直接写入)

Beats 是采集层:靠近数据源部署,读取文件、采集指标、接收网络数据,把原始数据发往下游。Filebeat、Metricbeat、Packetbeat 各自只做一件事。

Ingest Pipeline 是 ES 内部的轻量变换层:当索引文档时,ES 节点可以先把文档交给 pipeline 处理,再写入分片。它没有独立进程、没有磁盘队列,处理能力受 ES 集群节点资源约束。

Logstash 是独立的重量级 ETL 引擎:JVM 进程、持久队列、多输入多输出、条件路由、200 多个插件,是三者里能力最强、资源消耗也最高的。

资源对比

三者的资源消耗差距极大:

组件 运行时 典型内存占用 启动时间
Filebeat Go 原生 ~50–100 MB < 1 s
Metricbeat Go 原生 ~50–150 MB < 1 s
Ingest Pipeline 运行在 ES 节点内 共享 ES JVM 堆 无独立启动
Logstash JVM + JRuby 1–8 GB heap(默认 1 GB) 15–60 s

Beats 的低资源消耗让它可以在每台主机上部署,作为 sidecar 紧贴数据源。Logstash 的 JVM 开销决定了它通常作为中心化聚合节点运行,而不是每台机器各跑一个实例。

Beats:边缘采集的设计

Beats 系列各成员的共同特征:

1
2
3
4
5
6
7
8
9
10
11
12
13
Beats 内部结构
┌────────────────────────────────────────────┐
│ Input (harvester) │
│ 读文件 / 采集指标 / 监听网络 │
│ │ │
│ Publisher Queue (内存) │
│ │ │
│ Output │ │
│ ├── Elasticsearch(可带 ingest pipeline)│
│ ├── Logstash │
│ ├── Kafka │
│ └── Redis / 文件 │
└────────────────────────────────────────────┘

Filebeat 的核心机制是 harvester + registry。harvester 读文件,registry 记录每个文件的读取偏移量(inode + offset),实现断点续传。Beats 向下游确认送达后才推进 registry,这是其 at-least-once 的保证机制。

Beats 的处理能力是有限的:只能做极简单的字段添加(add_fields)、事件类型标记(event.type)和少量内置模块提供的字段映射。复杂的正则解析、多字段关联、聚合、跨源路由,超出了 Beats 的设计范围。

Ingest Pipeline:ES 内部的轻量变换

Ingest Pipeline 是 ES 5.0 引入的功能,让文档在被索引前先经过一组 processor 处理:

1
2
3
4
5
6
7
8
9
10
11
12
PUT /_ingest/pipeline/parse-nginx
{
"processors": [
{ "grok": { "field": "message",
"patterns": ["%{COMBINEDAPACHELOG}"] } },
{ "date": { "field": "timestamp",
"formats": ["dd/MMM/yyyy:HH:mm:ss Z"] } },
{ "set": { "field": "event.kind",
"value": "event" } },
{ "remove": { "field": "message" } }
]
}

常用 processor:grokdatesetremoverenamesplitconvertgeoipuser_agentscript(Painless)。

Ingest Pipeline 的关键约束:

  • 没有独立进程:pipeline 在 ES 的 ingest 节点上执行,消耗的是 ES 的 CPU 和内存,重计算会影响索引性能。
  • 没有持久队列:文档在 bulk 请求里进来,处理失败可以配置 on_failure,但没有 Logstash 那样的磁盘队列缓冲。
  • 单一输出:处理完的文档只能写进当前 ES 集群,无法路由到 Kafka、另一个 ES 集群或文件。
  • 没有多输入聚合:每个 pipeline 处理单个文档,不能跨文档做聚合或关联。

决策矩阵

1
2
3
4
5
6
7
8
9
10
场景                                 推荐路径
─────────────────────────────────────────────────────────────────
纯日志采集,不做任何变换 Beats ──▶ ES
轻量解析(一个 grok + date) Beats ──▶ ES + Ingest Pipeline
字段补充(geoip、user_agent) Beats ──▶ ES + Ingest Pipeline
多来源汇总 + 统一字段归一化 Beats ──▶ Logstash ──▶ ES
复杂条件路由(按内容写不同索引/集群) Logstash
写多个输出(ES + Kafka + S3) Logstash
需要 PQ 兜底(数据不可重放的源) Logstash(开启 PQ)
复杂聚合、跨事件关联 Logstash 或 Flink/Spark

一个实用的判断顺序:先问"需要写多少个不同的目标"——需要多目标输出的,只有 Logstash 能做。再问"变换有多复杂"——超过两个 processor 的链条、有条件分支的,Ingest Pipeline 的可维护性下降,Logstash filter 更适合。最后问"资源预算"——每台机器都要跑的场景,只有 Beats 可接受。

三路径组合:Beats → Logstash → ES

最常见的生产部署是三层叠加:

1
2
3
4
[应用服务器]                [中心处理节点]              [存储]
Filebeat ──┐
Filebeat ──┼──▶ Logstash ──▶ Elasticsearch
Metricbeat─┘ (filter + PQ)

Beats 在每台机器上以极低资源运行,负责文件读取和断点续传;Logstash 作为中心聚合节点,汇总多台机器的日志,做复杂解析和路由;ES 只负责存储和查询。

这种部署把各层的关注点分离:Beats 解决"如何可靠地把文件内容送出来",Logstash 解决"如何把杂乱数据变成结构化文档",ES 解决"如何存储和查询"。

Beats 直连 ES 时可以同时指定 Ingest Pipeline,在文档被 ES 接收时做轻量处理。这条路可以省去 Logstash 进程,但代价是处理逻辑分散在 Beats 配置和 ES pipeline 两处,调试成本上升。

模式提炼

1
2
3
4
5
6
7
8
9
10
11
模式:按资源边界分层,按能力上限路由

- 边缘层(每台机器):用资源消耗极低的工具,只做采集和传输
- 中间层(集中部署):用有能力做复杂变换、有队列缓冲的工具
- 存储层(ES):把简单的字段变换内嵌为 Ingest Pipeline,减少外部进程数

决策依据:
能力不够 → 往能力更强的层上移
资源超出 → 往更轻量的组件替换
输出单一 → Ingest Pipeline 可以承担
输出多个 → 必须走 Logstash 或同等能力的中间件

这个模式不局限于 Elastic Stack。AWS 的 Kinesis Firehose(边缘传输)+ Lambda(轻量变换)+ S3/Redshift(存储)是同一个三层结构的云原生版本。

工程迁移表

能力维度 Beats Ingest Pipeline Logstash
资源占用 极低(Go 原生) 共享 ES 节点 高(JVM,默认 1 GB heap)
部署位置 每台数据源机器 ES 节点内 独立中心节点
字段变换能力 极简(内置模块) 中等(20+ processor) 强(200+ 插件,条件分支)
多输入聚合
多输出路由 否(单一 output) 否(只进 ES)
持久队列 否(registry 续传) 是(PQ + DLQ)
条件路由 有限(if processor) 是(完整条件语法)
启动开销 可忽略 无独立启动 15–60 s

常见误解

误解一:“Beats 只是 Logstash 的简化版”。两者的设计定位不同,不是同一产品的高低配。Beats 是轻量边缘采集器,Logstash 是重量中心处理器,在架构里处于不同的层,通常配合使用而不是互相替代。

误解二:“Ingest Pipeline 可以替代 Logstash 做所有解析”。Ingest Pipeline 缺少持久队列、多目标输出和复杂条件路由。当解析逻辑超过两三个 processor 的简单链条、或者需要写多个目标时,Ingest Pipeline 就不够用了。

误解三:“每台机器都应该跑 Logstash”。Logstash 的 JVM 开销在每台机器部署时通常无法接受。每台机器跑 Beats,集中部署 Logstash,是资源与能力的合理分配。

误解四:“Beats 没有可靠性保证”。Filebeat 的 registry 机制保证了文件读取的断点续传,配合 Logstash 的 ACK 或 ES 的确认机制,可以实现端到端 at-least-once。说"Beats 会丢数据"是对其可靠性机制的误解,但它的可靠性依赖下游 output 的 ACK,不像 Logstash PQ 那样在进程本地就有落盘缓冲。

练习

  1. 搭建一个 Filebeat → ES 的最小管道,在 Filebeat 的 output 里配置 pipeline: parse-nginx,用第二节的 parse-nginx pipeline 对采集到的 nginx 日志做 grok 解析。对比在 Logstash 里做同样解析的配置量差异,记录两种方式的行数和调试难度。

  2. 把练习 1 的 Filebeat 改成 Filebeat → Logstash → ES,在 Logstash 里用 grok filter 做同样的解析,并加一个条件路由:status >= 500 的事件额外发一份到另一个 ES 索引(模拟告警通道)。观察 Ingest Pipeline 无法满足这个需求的原因。

  3. 思考题:给定场景——50 台应用服务器每台产生日志,日志需要解析后写入两个 ES 集群(生产和归档)。对比三种方案的资源消耗和运维复杂度:(a) 每台跑 Logstash;(b) 每台跑 Filebeat,中心跑 2 台 Logstash;© 每台跑 Filebeat 直连 ES + Ingest Pipeline,另外用 Logstash 处理需要写双集群的部分。

系列导航

序号 主题 状态
00 导读:核心对象是 event,骨架是三段管道 已发布
01–03 核心抽象(架构 / event 模型 / codec) 已发布
04–08 插件三段(input / Grok / dissect / 常用 filter / ES output) 已发布
09–12 管道可靠性(worker·batch·背压 / 队列 / DLQ / Multiple Pipelines) 已发布
13–14 运维、监控与调优 已发布
15 Logstash vs Beats vs Ingest Pipeline:该用谁 本篇
16 Logstash vs Fluentd vs Vector:日志管道的三种取舍 下一篇
17 Logstash 的演进与 Elastic Agent 的冲击

参考资料