跳到正文

ES 监控指标与告警 ​

一句话:ES 的监控不是看进程活没活,而是盯住「队列、堆、磁盘、分片状态」这四个会互相放大的资源;雪崩几乎都从一次排队或一次水位越线开始。

适用版本:Elasticsearch 8.x。指标名、默认值以官方 Monitoring、cat APIs 与线程池文档为准;文中阈值只是起点,必须按自己的基线校准。

为什么需要 ​

ES 是「近实时 + 不可变段」的分布式检索系统:一次写入要经过 buffer、refresh、translog、merge,一次查询要扇出到多个分片再归并。资源不是孤立消耗的——队列积压推高延迟,延迟让客户端重试,重试继续推高队列;堆压力让 GC 变长,GC 停顿又让请求排队。等 _cluster/health 变红再处理,通常已经进入「重启也要很久才能恢复」的阶段。监控的价值,是提前看见那条放大链的第一环。

核心机制 ​

指标分三层看 ​

层关键指标它反映什么
集群_cluster/health 的 status、unassigned_shards、relocating_shards、initializing_shards分片是否齐全、是否在搬移或恢复;yellow 是副本缺失,red 是主分片缺失
节点_nodes/stats/jvm 的 heap used 与 GC 时间;thread_pool.write/search 的 queue、rejected;indices.search.query_total/time_in_millis;indices.indexing.index_total;fs 可用空间;breakers 的 tripped单节点是否成为瓶颈:堆、线程池、磁盘、熔断
索引_cat/indices 的 health、docs.count、store.size、pri/rep;_cat/segments 的段数;_cat/shards;_cat/allocation;_cat/thread_pool哪个索引在膨胀、哪个分片没分配、哪个节点分片过多

分片数要单独看:_cat/indices 不直接给段数,段数用 _cat/segments 或 _nodes/stats/indices/segments。单分片段数长期只增不减,通常意味着 merge 跟不上写入。

指标怎么连成雪崩 ​

图里真正致命的是 rejected → 重试 → 队列更满 这个正反馈:rejected 本来是线程池的保护动作,客户端把它当成瞬时错误立即重发,就把保护变成了放大器。右侧那条链则说明写入和查询并不隔离,merge 与 refresh 吃掉的 IO 和堆,最后会以查询超时的形式出现。

五条典型恶化链路 ​

  • 写入队列:并发或单次 bulk 过大 → thread_pool.write.queue 上升 → rejected 增加 → 客户端重试 → 队列更深。8.x 默认 write 队列 10000、search 队列 1000,队列有界是设计,不是缺陷。
  • 堆压力:大聚合、深分页、text 字段排序走 fielddata → 老年代增长 → 长 GC → 请求堆积 → 熔断。默认总熔断 70%、fielddata 40%、request 60%,跳闸说明堆已经不够用。
  • 磁盘与 IO:持续写入叠加 merge → IO 饱和 → refresh 变慢、translog 增长 → 磁盘越过 85%/90%/95% 水位 → 停止分配、尝试迁移、索引只读。
  • 分片状态:节点掉线 → 副本或主分片未分配 → 恢复受并发与带宽限制(默认每节点 2 个并发恢复、40MB/s,按官方文档) → 长时间 yellow/red。主分片丢失时写入直接失败。
  • mapping 膨胀:动态 mapping 长出上千字段 → cluster state 变大 → master 发布状态变慢 → 集群操作抖动,同时每个字段的索引与 doc_values 都在吃堆。

慢日志、热点线程与后台任务 ​

慢日志默认关闭(index.search.slowlog.threshold.* 与 index.indexing.slowlog.threshold.* 默认为 -1),必须显式打开才能留下查询/写入证据;_nodes/hot_threads 用来看「此刻」哪个线程在烧 CPU。ILM 与快照失败不会让集群变红,却会让磁盘悄悄涨满:用 GET _ilm/status、GET _ilm/explain、GET _slm/status、GET _snapshot/_status 单独巡检。

最小上手 ​

bash
# 单节点即可验证(8.x,关闭安全认证仅用于本地)
docker run -d --name es -p 9200:9200 \
  -e discovery.type=single-node -e xpack.security.enabled=false \
  docker.elastic.co/elasticsearch/elasticsearch:8.15.0

curl -s "localhost:9200/_cluster/health?pretty"
curl -s "localhost:9200/_cat/indices?v&h=health,index,pri,rep,docs.count,store.size"
curl -s "localhost:9200/_nodes/stats/jvm,thread_pool,fs,breaker?pretty"
curl -s "localhost:9200/_cat/thread_pool/write,search?v&h=node_name,name,active,queue,rejected"
curl -s "localhost:9200/_cat/shards?v&h=index,shard,prirep,state,unassigned.reason,node"
curl -s "localhost:9200/_nodes/hot_threads"

预期:单节点 status 为 green(无副本)或 yellow(有副本但无处分配);queue 应接近 0,rejected 不增长;fs 的可用空间要明显高于 15%。

接 Prometheus 时用 elasticsearch_exporter,典型告警表达式(指标名以 exporter 版本为准):

promql
elasticsearch_cluster_health_status{color="green"} == 0
elasticsearch_jvm_memory_used_bytes{area="heap"}
  / elasticsearch_jvm_memory_max_bytes{area="heap"} > 0.75
rate(elasticsearch_thread_pool_rejected_count{type="write"}[5m]) > 0
elasticsearch_filesystem_data_available_bytes
  / elasticsearch_filesystem_data_size_bytes < 0.25

生产动作 ​

告警清单(8–10 条) ​

告警起点(按基线校准)为什么是先兆
集群 status 非 greenred 持续 1 分钟;yellow 持续 10 分钟主分片缺失会直接丢写入,副本缺失降低容灾
未分配分片任一副本未分配 10 分钟;主分片未分配立即告警恢复可能卡在磁盘、机架或分配规则上
JVM heap 使用率持续 10 分钟 > 75%接近熔断与长 GC,先于查询失败出现
old GC 时间占比持续 5 分钟 > 5%GC 停顿会同时抬高写入与查询延迟
write/search rejected5 分钟内出现非零速率队列已满,重试会形成正反馈
circuit breaker tripped任意一次堆已无法满足某类请求,查询会成片失败
磁盘可用空间< 25%,早于 85% low watermark到 95% 就只读,届时只能删数据或扩盘
查询延迟与慢日志P99 超基线 2 倍,或慢日志突增往往是 merge、GC 或分片热点的最早外显
ILM / SLM / snapshot 失败任意失败或 ILM 处于 STOPPED不告警就会以磁盘写满的形式暴露
mapping 字段数接近默认上限 1000cluster state 与堆开销会非线性放大

处置顺序 ​

  1. 先分清读还是写。读慢时扩容数据节点可能触发大量分片迁移,反而更慢;写 rejected 时先降载通常比加节点更快见效。
  2. 写入 rejected:客户端指数退避、把 bulk 控制在 5–15MB、降低并发、暂停批量导入;仍不够再扩数据节点或 rollover 新索引。不要靠调大队列「解决」,那只是把内存问题推迟。
  3. 堆压力:先停重聚合与深分页、缩小 size、避免 text 排序,再考虑扩节点。重启单个节点前先确认副本可承接,否则会短暂变红。
  4. 磁盘水位:删/关闭旧索引、让 ILM 正常滚动、扩盘;不要关闭 watermark 保护来「先写进去」。
  5. 集群 red:先 _cluster/allocation/explain 看 decider 拒绝原因,恢复节点或磁盘,再谈 reroute;强制 reroute 可能把分片放到不满足机架或磁盘条件的位置。
  6. 重启风险:节点重启后堆是冷的,分片恢复会占用网络与 IO,master 重启还会触发状态重新发布。滚动重启时逐个节点进行,必要时先把分配限制为主分片,恢复后再放开。

长处与代价 ​

ES 的长处是倒排索引 + 分布式聚合:全文相关性、过滤、聚合、日志分析在同一引擎里完成,水平扩展成熟。代价同样明确:

  • 近实时而非实时,默认 refresh 1 秒,写后立即可查要额外等待或显式 refresh。
  • 更新是「标记旧文档 + 写新文档」,频繁更新/删除会放大段与 merge 成本。
  • 堆、磁盘、IO 都重,分片数和 mapping 一旦设计错,后期修改成本很高。
  • 没有跨文档事务,join 能力弱,不适合当主业务库。
适用不适用
全文检索、站内搜索、日志与可观测分析需要事务、强约束、频繁更新的主业务库
过滤 + 聚合 + 排序组合较多的查询写后必须立刻读到最新值的场景
已有 ES,想做关键词与向量混合检索超大规模纯向量、且团队没有 ES 运维经验
数据量中等、需要成熟生态与可视化复杂多表 join、以点查为主的 OLTP

边界 ​

  • 监控指标只能告诉你「哪里不平衡」,不能替代压测与容量规划;同样的 heap 百分比,在不同查询组合下含义不同。
  • 阈值必须按基线校准,照搬别家的 75%、5% 往往会误报或漏报。
  • 不同 exporter 版本的指标名有差异,落地前先用 /metrics 核对。
  • 集群 green 不等于业务可用:慢查询、mapping 爆炸、ILM 卡住都可能在全绿时发生。

讲清楚 ​

ES 的监控要盯住四个会互相放大的资源:线程池队列、JVM 堆、磁盘水位、分片状态。写入侧最危险的是队列满后客户端立即重试,rejected 本来在保护集群,重试却把它变成雪崩的放大器;堆侧是聚合和深分页把老年代推高,长 GC 之后熔断跳闸;磁盘侧是 merge 与 refresh 吃满 IO,水位越线后索引只读;分片侧是节点掉线后恢复受并发与带宽限制,长时间 yellow 或 red。

处置要先分清读写:写 rejected 先降载、退避、缩小 bulk,再扩容;堆压力先停重查询;磁盘先删旧索引或扩盘,不要关水位保护;red 先看 allocation explain。重启不是首选,冷堆和分片恢复会让问题短暂更糟。ES 强在全文检索、聚合与日志分析,代价是近实时、更新昂贵、资源重,mapping 与分片设计错了很难回头。

把一门技术讲透到既懂也会用