ELK 不是三个软件的合集,而是一条「采集 → 加工 → 存储 → 检索 → 展现/告警」的流水线: Logstash 负责把杂乱日志变成带结构的 JSON,Elasticsearch 负责把它存下来并在秒级内全文检索, Kibana 负责把人能从里面看出问题。三者通过 HTTP/JSON 解耦,任何一段都能被替换或旁路。
2026 年必须知道的三件事:
logs-*-* data stream 默认启用 logsdb 索引模式(更省空间、写入略慢);官方实测节省 44%,配合 synthetic _source 的生产 benchmark 达 76%(162.7 GB → 39.4 GB)。type/fields/copy_to/boost、client.type、旧的 _knn_search API 等);Logstash 9.4.0 起 要求 Java 21,Java 17 不再支持。如果你做过 CI/CD 和容器运维,下面这张对照表就是整篇文档的地图。左边是你已经会的东西,右边是 ELK 里的同构概念——执行 = f(配置, 状态),ELK 的全部复杂度都来自「配置」如何决定「状态」的分布。
| 你熟悉的世界 | ELK 里的对应物 | 关键差异(坑在这里) |
|---|---|---|
| Jenkins Pipeline / GitLab CI Job | Logstash pipeline(input → filter → output) | 一次跑一条流水线是「一次性」的;Logstash 是常驻进程,7×24 消费事件流,失败要能重放 |
| node_exporter / Telegraf | Filebeat / Metricbeat / Elastic Agent | 只采集、几乎不加工,资源占用极小;加工放后面(Logstash 或 Elasticsearch ingest pipeline) |
| Grafana 面板 | Kibana Dashboard(Lens 可视化) | Kibana 同时是「前端 + 管理后台」,权限/索引模板/ILM 都在同一个 UI 里 |
| MySQL 表 / 行 / DDL | index / document / mapping | mapping 一旦建好基本不可改,改字段类型只能新建索引再 reindex——像不可变 schema |
| 分库分表的分片 | shard(主分片)+ replica(副本分片) | 分片数在索引创建时定死(_shrink/_split 可调整但代价大);分片过多本身就会拖慢集群 |
| MySQL 分区表 / logrotate 归档 | data stream + ILM(hot→warm→cold→frozen→delete) | data stream 是「只追加」的:写入自动进最新 backing index,不能随意 update/delete 单条 |
| SQL | Query DSL / ES|QL(管道式新查询语言) | ES|QL 是 9.x 的主力查询语言:类 SQL 但对日志/时序更自然,Kibana 的 Discover、仪表盘、告警都能用 |
| 日志文件本身 | _source(文档原文)+ 倒排索引 + doc_values | _source 可被合成(synthetic)以省空间,代价是字段顺序等细节不再保真 |
flowchart LR
subgraph SRC["数据源"]
A1["应用日志文件"]
A2["容器 stdout/stderr"]
A3["系统与中间件指标"]
A4["应用链路 trace"]
end
subgraph SHIP["采集层 轻量 常驻"]
B1["Filebeat"]
B2["Metricbeat"]
B3["Elastic Agent<br/>内建 OTel Collector"]
end
subgraph PROC["加工层 可选 可放大"]
C1["Logstash<br/>grok / dissect / enrich"]
C2["Elasticsearch<br/>ingest pipeline"]
C3["消息队列<br/>Kafka / Redis 缓冲"]
end
subgraph STORE["存储与检索"]
D1["Elasticsearch 集群<br/>data stream + ILM"]
D2["对象存储<br/>searchable snapshot"]
end
subgraph VIEW["展现与告警"]
E1["Kibana<br/>Discover / Lens / 仪表盘"]
E2["告警与连接器<br/>邮件 / Webhook / Slack"]
end
A1 --> B1
A2 --> B3
A3 --> B2
A4 --> B3
B1 --> C3
B2 --> C2
B3 --> C3
C3 --> C1
C1 --> D1
B1 -.->|"轻量场景直连"| D1
B3 -.->|"Agent 直连"| D1
C2 --> D1
D1 --> D2
D1 --> E1
E1 --> E2
E2 -.->|"人到现场处理"| SRC三点工程判据:
sequenceDiagram
autonumber
participant APP as 业务应用
participant SHIP as Filebeat / Elastic Agent
participant MQ as Kafka(可选)
participant LS as Logstash
participant ES as Elasticsearch
participant KB as Kibana
APP->>SHIP: 追加写日志文件或 stdout
Note over SHIP: 记忆位点 断点续传
SHIP->>SHIP: 多行合并 + 加 host 元数据
SHIP->>MQ: 投递事件(或直连 ES 的 bulk 接口)
MQ->>LS: 消费者拉取
LS->>LS: grok 解析 + date 归一化 + mutate 清洗
LS->>ES: bulk 批量写 data stream
Note over ES: ingest pipeline 再加工<br/>按时间戳路由到 backing index
ES->>ES: 写入内存 buffer 与 translog
ES-->>KB: refresh 后可见 默认约 1 秒
Note over LS,ES: 写入失败 400/404 → DLQ 死信队列
KB->>ES: ES|QL 或 Query DSL 查询
ES-->>KB: 命中结果 + 聚合
KB->>KB: Lens 渲染仪表盘并触发告警规则
| 对象 | 是什么 | 工程含义 |
|---|---|---|
| document | 一条 JSON 记录(一条日志 = 一个文档) | 字段名决定一切,字段名一乱,Kibana 面板就废 |
| index | 文档的集合,背后是若干 Lucene 段 | 真的「表」,但 schema(mapping)不可变 |
| shard | Lucene 索引实例,分布在节点上 | 并行度的单位,也是故障恢复的单位;创建后数量基本固定 |
| replica | 主分片的副本,跨节点 | 高可用 + 提升查询吞吐;副本数可随时改 |
flowchart TD
W["index / bulk 请求"] --> IB["内存索引缓冲<br/>in-memory buffer"]
W --> TL["translog 事务日志<br/>每次写都落盘"]
IB -->|"refresh 默认约 1 秒"| SEG["新 segment<br/>先写文件系统缓存"]
SEG --> SEARCH["可被搜索<br/>近实时生效"]
SEG -->|"flush / commit"| DISK["落盘 fsync"]
TL -->|"节点重启恢复"| IB
SEG -->|"后台 merge"| M["合并成大 segment<br/>删除已标记文档"]
M --> SEARCH_forcemerge?only_expunge_deletes=true 或让 ILM 在 warm 阶段做 force merge。flowchart LR
C["Kibana 发起查询"] --> CO["协调节点<br/>coordinating"]
CO -->|"并发扇出"| P1["主分片 1<br/>本地查询"]
CO -->|"并发扇出"| P2["主分片 2<br/>本地查询"]
CO -->|"并发扇出"| P3["主分片 N<br/>本地查询"]
P1 --> MERGE["归并排序 / 聚合合并"]
P2 --> MERGE
P3 --> MERGE
MERGE --> TOP["返回 top-N 与聚合结果"]
CO -.->|"默认读取路径"| R["副本分片<br/>共同承担读流量"]
R --> MERGE结论:查询成本 ≈ 分片数 × 单分片成本。每个分片都要被打开、查、归并,因此「分片太多」(oversharding)是自建集群性能劣化的头号原因。官方给出的优化标尺:
| 变更 | 影响 |
|---|---|
mapping 元数据字段不再支持 type / fields / copy_to / boost | 老模板里带这些参数的自定义元数据字段,需要删掉后再建 |
client.type 节点设置被移除 | 节点客户端早在 8.0 就删了;elasticsearch.yml 里留着的这行会让节点起不来,删掉 |
旧 _knn_search 技术预览 API 移除 | 向量检索请用 knn 查询(_search 内) |
| 单节点磁盘水位设置被移除 | 磁盘水位相关设置只保留 multi-node / single-node 两种取值,升级前清理旧值 |
elser 推理服务弃用 | 用 elasticsearch 服务替代(稀疏向量/推理场景) |
来源:Elasticsearch 9.0.0 release notes(官方 9.0 安装与升级指南)。
Elasticsearch 自身带一个「写入前加工」环节,请求里带 ?pipeline=xxx 即触发;索引可声明 default pipeline 和 final pipeline。这层适合做轻量归一化(补字段、改类型、geoip),官方还提供 simulate API 在不写入的前提下验证 pipeline。
# 定义一个最简单的 ingest pipeline
PUT _ingest/pipeline/add_env
{
"description": "补齐环境字段",
"processors": [
{ "set": { "field": "service.environment", "value": "prod" } }
]
}
# 不写入、只验证:拿到处理后的文档
POST _ingest/pipeline/add_env/_simulate
{ "docs": [ { "_source": { "message": "hello" } } ] }
flowchart LR
IN["input 插件<br/>beats / kafka / file / tcp"] --> QB{"队列"}
QB -->|"默认 memory 快 但重启丢"| F1["filter worker 1"]
QB -->|"persisted 慢 但可恢复"| F2["filter worker 2"]
F1 --> OUT["output 插件<br/>elasticsearch / kafka"]
F2 --> OUT
OUT -->|"成功"| ES["Elasticsearch"]
OUT -->|"400 / 404 类失败"| DLQ["DLQ 死信队列<br/>落盘待重放"]
OUT -->|"ES 不可用"| RETRY["重试并阻塞<br/>上游压力回传"]
DLQ -->|"专用 pipeline 读取"| OUT| 机制 | 官方口径 | 实务建议 |
|---|---|---|
| 内存队列(默认) | 快,但进程重启未处理事件会丢 | 可接受的丢日志场景(调试环境、可重放源)用默认 |
| 持久化队列 PQ | 磁盘队列,重启可恢复;官方提供 pqrepair 工具修复损坏队列 | 金融/审计类日志必开;注意磁盘占用与吞吐下降 |
| 死信队列 DLQ | 专收 Elasticsearch 返回 400 / 404 这类「重试也没用」的事件 | 不打开 DLQ 时,这些事件在日志里刷屏然后消失;打开后用专有 pipeline 消费它们定位 mapping 冲突 |
input {
beats { port => 5044 }
}
filter {
# 1) 结构化解析:优先 dissect(快),格式不稳再用 grok(慢但灵活)
grok {
match => {
"message" => "%{IPORHOST:client.ip} %{WORD:http.request.method} %{URIPATHPARAM:url.path} %{NUMBER:http.response.status_code:int}"
}
}
# 2) 时间归一化:把日志里的时间变成 @timestamp,否则按采集时间算
date { match => [ "log_time", "ISO8601", "UNIX_MS" ] }
# 3) 清洗与降噪
mutate {
remove_field => [ "agent.ephemeral_id", "host.os" ]
rename => { "log_level" => "log.level" } # 对齐 ECS 命名
}
if [log][level] == "DEBUG" { drop { } } # 源头降量,比事后删索引便宜
}
output {
elasticsearch {
hosts => ["https://es-node-1:9200", "https://es-node-2:9200"]
data_stream => "true" # 走 data stream 路由
data_stream_type => "logs"
data_stream_dataset => "myapp.access"
data_stream_namespace => "prod"
# 目标 data stream: logs-myapp.access-prod
}
}
data_stream 默认即为 true;必须启用 ECS 兼容模式(ecs_compatibility 设为 v1 或 v8)data stream 才能正常工作。TLS 场景可用 ca_trusted_fingerprint 传 CA 的 SHA-256 指纹(需 Logstash 8.3+),省掉证书文件分发。| 项 | 官方口径 |
|---|---|
| 堆内存 | 典型摄入场景建议 不低于 4 GB、不高于 8 GB(堆之外还有 off-heap:线程栈、direct memory) |
| 线程模型 | 每个 pipeline 的 filter 线程池约 2 × CPU 核数;output 插件还会起自己的辅助线程 |
| Java 版本 | Logstash 9.4.0 起要求 Java 21(升级 JRuby 10 所致),Java 17 及以下不再支持 |
| Elasticsearch 堆 | 默认由角色与内存自动推导,官方推荐用默认值;手工覆盖时 Xms=Xmx 且 ≤ 总内存 50%,同时不超过压缩指针(compressed oops)阈值(多数系统 26 GB 安全,个别可到 30 GB) |
| Elasticsearch 进程内存 | 用 heap size [...], compressed ordinary object pointers [true] 日志行或 jvm.using_compressed_ordinary_object_pointers 自证没超阈值 |
flowchart LR
Q["查询入口<br/>Discover / 仪表盘筛选器"] --> LANG{"查询语言"}
LANG -->|"ESQL 推荐"| P1["管道式查询<br/>FROM / WHERE / STATS"]
LANG -->|"Query DSL"| P2["JSON 查询体"]
P1 --> KBS["Kibana 服务端<br/>注入数据视图与权限"]
P2 --> KBS
KBS --> ESL["Elasticsearch 集群"]
ESL --> RES["结果集"]
RES --> LENS["Lens 可视化<br/>多图层 可折叠为标签页"]
LENS --> DASH["Dashboard<br/>可设置 owner 与只写限制"]
RES --> ALERT["告警规则<br/>含基于 ES|QL 面板创建规则"]
ALERT --> CONN["连接器<br/>邮件 / Slack / Webhook"]| 版本 | 能力 | 对运维的意义 |
|---|---|---|
| 9.1 | 可从 ES|QL 仪表盘面板直接「创建告警规则」 | 从「看图」到「挂告警」不用再切到告警模块重写查询 |
| 9.2 | Discover 里的 ES|QL 查询支持变量控件;Kibana 新增 Streams 页统一管理 data stream | 数据流管理从「模板 + ILM + 索引」三处配置收敛到一个页面 |
| 9.3 | 仪表盘支持 owner 与 write_restricted(写成受限期);Lens 图层改为标签页布局 | 仪表盘可以「先内部编辑、再发布」,避免半成品被业务方看到并误信 |
| 9.4 | ES|QL 支持多 terms 图、Vega 可视化;ES|QL 图表支持仪表盘/URL 下钻 | 复杂分析不用再退回 Query DSL + 脚本聚合 |
| 支柱 | 数据形态 | Kibana 入口 |
|---|---|---|
| Logs | logs-*-* data stream(默认 logsdb) | Discover(日志视图)/ 对数速率异常检测 |
| Metrics | metrics-*-*(TSDS 时序流更省空间) | 基础设施视图 / Lens 时序图 |
| Traces | APM 数据(原生 agent 或 OTel/EDOT 汇入) | APM 应用视图(服务地图、事务、依赖) |
ECS(Elastic Common Schema)是把三者粘起来的关键:@timestamp、log.level、message、service.name、event.dataset(这个字段能开启日志速率异常检测)、error.* 等字段名统一了,面板与告警才能复用。官方特别区分三个时间戳的先后关系:@timestamp(事件发生) < event.created(采集器看到) < event.ingested(入库)。排查「日志延迟」时用 event.ingested - @timestamp 量化,别靠感觉。
flowchart TD
START["要采集什么"] --> T1{"需要同时采<br/>日志 + 指标 + trace 吗"}
T1 -->|"只要日志 且环境受限"| FB["Filebeat<br/>最省资源"]
T1 -->|"只要指标"| MB["Metricbeat"]
T1 -->|"都要 或要统一管理"| EA["Elastic Agent<br/>单一代理 集中策略"]
T1 -->|"要跨厂商 标准 OTel"| OT["OpenTelemetry Collector<br/>或 EDOT 发行版"]
EA --> O1{"9.2 起内建 OTel Collector"}
O1 -->|"agent 模式"| O2["主机本地采集<br/>贴近应用"]
O1 -->|"gateway 模式"| O3["集中式入口<br/>自管栈中替代 APM Server"]
OT --> O4["统一 OTLP 出口<br/>弹性对接多后端"]
FB --> DONE["写入 Elasticsearch<br/>或 Logstash"]
MB --> DONE
EA --> DONE
O2 --> DONE
O3 --> DONE
O4 --> DONE事实(官方文档):从 9.2 起,Elastic Agent 运行在内建的 OpenTelemetry Collector 之上(该能力来自 EDOT Collector,即「Elastic Distributions of OpenTelemetry」);官方同时提供 Beats → Elastic Agent 的迁移指南。EDOT 家族还包括各语言 SDK(Java / Python / .NET / Node.js / PHP / Android / iOS 已 GA,Browser 处于技术预览),以及面向云厂商的 Forwarder。
实务推论:新建集群就上 Elastic Agent;存量 Filebeat 不必连夜迁(Beats 仍在发布,9.3.8 于 2026-08-04 发布),但新项目的默认选择应该是 Agent;如果公司有「可观测性数据标准必须 OTel」的技术债要求,直接在 Agent 的 OTel 模式下用 OTLP 接入,避免以后再迁一次。
官方定义:data stream 是对一组针对「只追加时序数据」优化的索引的抽象层——你只对一个逻辑名字(如 logs-myapp-prod)读写,它自动路由到多个 backing index。适合它的三个判据:
_id,或带 _id 时接受「先写入者胜」。反例:需要频繁按 _id 覆盖写(后写入者胜)的场景,官方建议改用 index alias + write index。TSDS(时序数据流)与 data stream lifecycle 这类特性必须以 data stream 为前提。
flowchart LR
HOT["hot 热<br/>持续写入 可搜索"] -->|"rollover 达 50GB 或 30 天"| WARM["warm 温<br/>只读 可 shrink 合并段"]
WARM -->|"7 天后"| COLD["cold 冷<br/>查询少 迁到便宜硬件"]
COLD -->|"到期"| FROZEN["frozen 冻结<br/>可搜索快照 极慢但便宜"]
FROZEN -->|"保留期到达"| DEL["delete 删除"]
HOT -.->|"set_priority 提高优先级"| HOT
WARM -.->|"allocate 指定节点属性"| WARM
COLD -.->|"searchable snapshot"| COLD
DEL -.->|"wait_for_snapshot 先确保快照"| DEL| 动作 | hot | warm | cold | frozen | delete |
|---|---|---|---|---|---|
| rollover | ✅ | — | — | — | — |
| shrink / force merge | ✅ | ✅ | — | — | — |
| read-only / set priority / downsample | ✅ | ✅ | ✅ | — | — |
| allocate / migrate | — | ✅ | ✅ | — | — |
| searchable snapshot | ✅ | — | ✅ | ✅ | — |
| unfollow | ✅ | ✅ | ✅ | ✅ | — |
| wait for snapshot / delete | — | — | — | — | ✅ |
来源:官方「Index lifecycle management phases and actions」——这是一手表格,照它配策略就不会出现「在 delete 阶段配 rollover」这种无效配置。
官方给的典型策略示例:主分片到 50 GB 或 30 天 rollover → warm 阶段设为只读并 shrink 到单个分片 → 7 天后进 cold 迁到便宜硬件 → 保留期满删除。注意两条硬规则:(1) 后续阶段的 min_age 必须不小于前一阶段;(2) 手工挂在索引上的生命周期策略,在 rollover 产生新索引后不会自动继承——必须写在索引模板里。
事实(官方文档 + 官方实测):
logs-*-* data stream 自动使用 logsdb 索引模式;从 8.x 升级上来的集群里,存量 data stream 不会被自动切换,需要在相关的 @custom 组件模板里显式设置 index.mode: logsdb,下次 rollover 生效。host.name + @timestamp 排序、best_compression 压缩、ignore_malformed、ignore_above: 8191、动态字段超限不再抛错等。index.mode: logsdb 设置即带来 44% 存储节省(官方动手实测);生产 benchmark 配合 synthetic _source 达 76%(162.7 GB → 39.4 GB)。对比 8.17 标准模式,9.1 的 logsdb 存储效率为 2.87 倍(基础)/3.83 倍(企业),索引吞吐中位数开销约 4.94%–11.64%。_source 是 Enterprise 功能(官方订阅页脚注:自 8.17 起属企业版特性)。免费的 Basic 授权下 logsdb 仍生效,但用原始 _source,省不到最狠的那 20%–40%。| 场景 | 要不要开 logsdb | 理由 |
|---|---|---|
| 应用日志、访问日志(海量、低价值密度) | 要(新集群默认已开) | 省磁盘是第一优先级,写入慢几个百分点可以接受 |
| 需要打满写入吞吐的极限场景 | 可评估关闭 | 索引吞吐有可测量开销;用真实流量压测后再定 |
| 依赖字段顺序/数组重复值保真的场景 | 谨慎 | synthetic _source 恢复出的字段顺序可能与原文不同;logsdb 默认 synthetic_source_keep: arrays 保留重复值与顺序,但数组元素/对象结构不保证保留 |
# 检查现有 data stream 是否已落进 logsdb 模式
GET /.ds-logs-*/_settings?filter_path=*.settings.index.mode
# 手工建一个 logsdb 索引(自测用)
PUT /my-logsdb
{ "settings": { "index.mode": "logsdb" } }
flowchart TB
LB["客户端 / Kibana / Beats"] --> CO["协调层<br/>coordinating 查询聚合"]
CO --> HL["hot 层<br/>SSD 高配<br/>写入与近期查询"]
CO --> WL["warm 层<br/>中等配置<br/>只读 已 merge"]
CO --> CL["cold / frozen 层<br/>大容量 HDD<br/>可搜索快照"]
HL --> ML["专用 master 节点<br/>3 台 奇数 只做集群决策"]
WL --> ML
CL --> ML
HL --> SNAP["快照仓库<br/>对象存储 S3/OSS/COS"]
ML --> SNAP
HL --> KBN["Kibana 实例"]| 维度 | 官方标尺 | 落地做法 |
|---|---|---|
| 分片体积 | 10 GB – 50 GB | ILM rollover 设 max_primary_shard_size: 50GB,让分片随数据自然增长 |
| 分片文档数 | 低于 2 亿 / 分片 | rollover 再加 max_docs 兜底(高基数小文档场景尤其重要) |
| ES 堆 | 默认自动推导(推荐);手工覆盖时 ≤ 50% 内存且 Xms=Xmx | 别抄「固定 16 GB」的老博客;用默认,然后看 GC 日志 |
| 压缩指针阈值 | ≤ 26 GB(多数系统安全,最多 30 GB) | 堆超过阈值后指针从 4 字节变 8 字节,内存效率反而下降 |
| master 节点 | 奇数台、专用角色 | 3 台专用 master,避免脑裂与数据节点抢占选主资源 |
部署形态三选一:
flowchart TD
REQ["用户请求 Kibana 某项功能"] --> S1{"该角色在此空间被授予<br/>功能权限吗"}
S1 -->|"没授予"| DENY["功能不可见"]
S1 -->|"授予"| S2{"该功能在当前空间<br/>被显示出来了吗"}
S2 -->|"被隐藏"| DENY2["功能不可见"]
S2 -->|"可见"| S3{"索引权限匹配吗<br/>read + view_index_metadata"}
S3 -->|"不匹配"| DENY3["查不到数据"]
S3 -->|"匹配"| S4{"有 DLS / FLS 限制吗<br/>付费功能"}
S4 -->|"有 文档或字段被过滤"| PART["只看到部分文档或字段"]
S4 -->|"没有"| OK["看到全部"]官方权限矩阵的原文结论:功能可用 = 角色授予了该功能 AND 该功能在当前空间可见;两个条件缺一不可。给出的读取建议是索引权限至少给 read + view_index_metadata。另外一条容易误解的规则:多个角色叠加是「并集」——再加一个角色不能减少权限,想收权只能改/删原有角色。
| 能力 | 订阅档位 | 说明 |
|---|---|---|
| 加密通信、RBAC、Kibana 空间、功能控制、File/native 认证、API key、流量加密 | Basic 免费 | 基础安全在免费版就有,自建集群不要裸奔 |
| 文档级安全 DLS / 字段级安全 FLS、SSO(SAML/OIDC/Kerberos/JWT)、ABAC、IP 过滤、审计日志 | Platinum 及以上 | 「同一个索引里不同团队只能看自己那部分日志」属于这一档 |
synthetic _source | Enterprise(8.17 起) | logsdb 最狠的省空间能力,免费版拿不到 |
| 基于机器学习异常检测 / SLO 的告警规则 | Platinum / Enterprise | 普通阈值告警不受此限 |
| 跨集群操作 | 需两端同档位 | 官方脚注:跨集群操作要求涉及的所有集群订阅档位一致 |
| Gold 档 | 已停售 | 新客户不可购;Platinum 也仅存量客户可续 |
注:档位以官方订阅页为准(本文按 2026 年 10 月页面对照);Elastic Cloud 的功能矩阵与自管版略有差异(如部分 frozen 层/ILM 能力在托管侧按档位划分)。
flowchart TD
P["问题现象"] --> Q1{"现象是哪一类"}
Q1 -->|"日志根本没出现"| A1{"源头有这条日志吗"}
A1 -->|"文件里就没有"| A2["不是 ELK 的问题<br/>回到应用侧"]
A1 -->|"文件里有"| A3{"采集器位点是否推进<br/>Filebeat registry / Agent 状态"}
A3 -->|"没推进"| A4["采集器挂了或权限不足<br/>看采集器自身日志"]
A3 -->|"推进了"| A5{"中间有 MQ 或 Logstash 吗"}
A5 -->|"有"| A6["查 DLQ 与 PQ<br/>400/404 类失败会堆在 DLQ"]
A5 -->|"没有"| A7["查 ES bulk 拒绝<br/>线程池或磁盘水位"]
Q1 -->|"集群状态异常"| B1{"颜色"}
B1 -->|"yellow"| B2["有副本未分配<br/>单节点集群属正常现象"]
B1 -->|"red"| B3["有主分片未分配<br/>查 allocation explain"]
B3 --> B4["常见原因<br/>磁盘水位 节点掉线 分片损坏"]
Q1 -->|"查询变慢"| C1{"是写入高峰还是长期"}
C1 -->|"写入高峰"| C2["检查 refresh 频率与 bulk 大小<br/>考虑加大 refresh_interval"]
C1 -->|"长期变慢"| C3{"分片是否过多"}
C3 -->|"是"| C4["强制合并或按 50GB 重新规划<br/>_forcemerge 只清墓碑文档"]
C3 -->|"否"| C5["看字段类型与查询写法<br/>keyword 与 text 用错会扫全量"]| 症状 | 最可能的根因 | 先跑哪条命令 |
|---|---|---|
| Kibana 搜不到刚发生的日志 | refresh 未到(默认约 1 秒)/ 没人查该索引就不刷新 / 采集器位点滞后 | 看 event.ingested - @timestamp 的差值,确认延迟在哪一段 |
| 集群 yellow | 副本分片未分配(单节点集群常见) | GET _cluster/allocation/explain |
| 集群 red | 主分片未分配:节点掉线、磁盘水位、分片损坏 | GET _cluster/health?level=indices + allocation explain |
Logstash 日志里刷 400 / 404 | mapping 冲突(字段类型不符)或目标索引不存在 | 查 DLQ;用 ingest simulate 校验后再放量 |
写入被拒 es_rejected_execution | bulk 线程池饱和 / 磁盘水位触顶 | 看线程池队列与磁盘水位,加节点或降级写入 |
| 查询长期慢 | 分片过多(oversharding)/ 字段类型选错(text 当 keyword 用) | 按 10–50 GB 重新规划,检查 mapping |
flowchart LR
L1["L1 跑起来<br/>docker compose 起三件套<br/>灌进一条日志并在 Discover 看到"] --> L2
L2["L2 采集与解析<br/>Filebeat 采 Nginx 日志<br/>Logstash grok 出字段<br/>画出第一张 Lens 图"] --> L3
L3["L3 规范与生命周期<br/>ECS 字段命名<br/>索引模板 + ILM 冷热<br/>data stream 与 rollover"] --> L4
L4["L4 性能与容量<br/>分片规划 10-50GB<br/>堆与 GC 观察<br/>bulk 与 refresh 调优<br/>logsdb 取舍"] --> L5
L5["L5 生产级运维<br/>RBAC 与空间隔离<br/>快照与恢复演练<br/>版本升级路线<br/>告警闭环与容量预估"]| 级别 | 能做什么 | 必须搞懂的机制 | 自测题 |
|---|---|---|---|
| L1 跑起来 | 本地起三件套,写入并检索到一条日志 | HTTP/JSON 接口、index 与 document、Discover 基本查询 | 为什么刚写入的文档可能查不到?(refresh) |
| L2 采集与解析 | 用 Filebeat + Logstash 采真实日志并结构化 | grok vs dissect、@timestamp 的来源、ECS 字段 | 日志时间显示成采集时间,是哪个 filter 漏了?(date) |
| L3 规范与生命周期 | 索引模板 + ILM + data stream 全自动滚动归档 | rollover 触发条件、min_age 单调性、mapping 不可变 | 改了字段类型,为什么必须 reindex? |
| L4 性能与容量 | 按 10–50 GB 规划分片、判断要不要 logsdb、定位变慢原因 | segment/merge、refresh 代价、查询扇出、堆与压缩指针 | 堆设 40 GB 会更快还是更慢?(更慢) |
| L5 生产级运维 | 多租户权限、快照恢复演练、版本升级、告警闭环 | RBAC 判定顺序、订阅边界、跨版本破坏性变更 | 9.0 升级前要删掉哪些历史设置? |
?refresh=wait_for 复现「立刻可见」。client.ip / url.path / http.response.status_code → 在 Kibana 画「状态码 Top 10」Lens 图。max_age: 1m 策略观察 backing index 真实滚动。| 版本 | 状态(2026-10-14) | 备注 |
|---|---|---|
| 9.5.x | 当前主线(9.5.5,2026-10-06) | 新部署选它 |
| 9.4.x | 仍受支持(9.4.8,2026-10-06 同日发布) | 9.0–9.3 已陆续终止维护 |
| 9.3 / 9.2 / 9.1 / 9.0 | 已 EOL(分别止于 2026-08-04 / 2026-05-05 / 2026-02-03 / 2025-10-23) | 还跑在这些版本上的集群应尽早升级 |
| 8.19.x | 最后的 8.x 线,维护至 2027-07-15 | 8.x 的「长期落脚点」,跨大版本升级的起点 |
| Beats 9.2 | 已 EOL(2026-05-05) | Beats 仍在发布(9.3.8 @ 2026-08-04),但官方路径已指向 Elastic Agent |
_source、frozen/searchable snapshot)里,后两项与实测最狠的省法都涉及付费档或额外调优,预算评估要按实际情况算,别按「免费版 = 全部能力」估算。学 ELK 的正确顺序是「链路优先、组件其次」:先搞清一条日志从文件到 Kibana 的每一段(图 2),再逐个补组件细节——因为 90% 的线上问题都能靠这张链路图定位到具体那一段。三件套里 Elasticsearch 是唯一不可替换的(数据在这里、检索在这里),Logstash 在结构化日志时代已可被 ingest pipeline 或采集器自带解析替代,Kibana 则是「你做得好不好别人看不见、做不好别人立刻看得见」的那一层——面板与字段规范(ECS)的实际价值高于任何调优参数。
给自建集群的三条优先动作:(1) 先确认版本是否还在支持窗口,不在就排升级计划;(2) 把 ILM 与索引模板配全,别让索引无限增长(这是最容易拖垮集群、也最容易被忽略的一条);(3) 快照 + 恢复演练,只做快照不做恢复演练等于没有备份。
观察窗口:任何一个自建 ELK 集群,若连续 30 天出现「磁盘水位告警」或「分片数增长超过日志量增长」,说明生命周期策略或分片规划已经失控,此时调参无用,需要重做模板层。
| 主题 | 一手来源 |
|---|---|
| 版本与生命周期 | elastic.co/blog(Elastic Stack 9.5.5,2026-10-06)· endoflife.date/elasticsearch · endoflife.date/beats |
| 9.0 破坏性变更 | elastic.co/guide/en/elastic-stack/9.0/release-notes-elasticsearch-9.0.0.html |
| 近实时搜索与 refresh | elastic.co/docs/manage-data/data-store/near-real-time-search |
| data stream | elastic.co/docs/manage-data/data-store/data-streams |
| logsdb 与默认设置 | elastic.co/docs/manage-data/data-store/data-streams/logs-data-stream-configure · elastic.co/observability-labs(LogsDB 实测)· elastic.co/search-labs(8.19/9.1 性能对比) |
| 分片规划 | elastic.co/docs/deploy-manage/production-guidance/optimize-performance/size-shards |
| ILM 阶段与动作 | elastic.co/docs/manage-data/lifecycle/index-lifecycle-management/index-lifecycle |
| JVM/堆设置 | elastic.co/docs/reference/elasticsearch/jvm-settings · elastic.co/docs/deploy-manage/deploy/self-managed/important-settings-configuration |
| Logstash JVM 与 Java 版本 | elastic.co/guide/en/logstash/8.19/jvm-settings.html · elastic.co/docs/release-notes/logstash(9.4.0 要求 Java 21) |
| Logstash PQ / DLQ | elastic.co/docs/reference/logstash/persistent-queues · elastic.co/guide/en/logstash/8.19/dead-letter-queues.html |
| Elasticsearch output 插件 data_stream 选项 | elastic.co/docs/reference/logstash/plugins/plugins-outputs-elasticsearch(v12.1.6,2026-07-06) |
| ingest pipeline / simulate | elastic.co/docs/api/doc/elasticsearch/operation/operation-ingest-simulate |
| Kibana 版本特性 | elastic.co/docs/release-notes/kibana(9.1–9.5) |
| RBAC / 空间与角色 | elastic.co/docs/deploy-manage/users-roles/cluster-or-deployment-auth/kibana-role-management |
| Elastic Agent 内建 OTel Collector、Beats 迁移 | elastic.co/docs/reference/opentelemetry · elastic.co/what-is/edot · elastic.co/docs/reference/fleet/migrate-from-beats-to-elastic-agent |
| 订阅档位功能矩阵 | elastic.co/subscriptions(含 synthetic _source 自 8.17 起为 Enterprise 的脚注) |
| ECS 字段 | elastic.co/docs/reference/ecs · elastic.co/guide/en/ecs-logging(log.level / event.dataset / 三个时间戳) |