ES 核心监控指标
ES 核心监控指标
Elasticsearch 集群上线后,如果没有一套完善的监控体系,故障排查就变成"盲人摸象"。本文梳理了 ES 运维中最核心的 7 大类监控指标,以及接入 Prometheus + Grafana 的落地方案。
1. Heap 使用率
ES 是 Java 应用,堆内存(Heap)用满后会触发 OOM(OutOfMemory),节点直接挂掉。
| 阈值 | 状态 | 说明 |
|---|---|---|
| < 75% | 正常 | 安全水位 |
| 75% ~ 85% | 关注 | 需要排查是否有大查询或 bulk 堆积 |
| > 85% | 告警 | 随时可能 Full GC,应该立刻扩容或限流 |
| > 95% | 严重 | 随时 OOM |
配置建议:Heap 大小不超过物理内存的 50%,且不超过 32GB(受限于 JVM 压缩指针)。
# jvm.options
-Xms16g
-Xmx16g
查看方式:
GET /_nodes/stats/jvm
关键字段:jvm.mem.heap_used_percent。
踩坑案例:某次上线后发现节点每隔几分钟就 GC 一次,查看监控发现 Heap 使用率一直 92% 以上。追溯发现有人在
terms聚合里用了size: 10000,一次查询就加载了几十万个桶到内存中。解决方法是把size降到 100,并加了execution_hint: map。
2. GC 频率和耗时
ES 使用 G1GC(推荐)或 CMS。重点关注 old GC 频率和单次 old GC 耗时。
| 指标 | 正常值 | 告警阈值 |
|---|---|---|
| Young GC 频率 | < 10 次/分钟 | > 30 次/分钟 |
| Young GC 耗时 | < 100ms | > 500ms |
| Old GC 频率 | 0 ~ 偶尔 | > 1 次/10分钟 |
| Old GC 耗时 | < 500ms | > 1s |
查看方式:
GET /_nodes/stats/jvm
关键字段:jvm.gc.collectors.old.collection_count 和 collection_time_in_millis。
踩坑案例:使用 CMS 时,某次数据迁移 bulk 写入过快,old 区来不及回收,触发 Concurrent Mode Failure,单次 GC 耗时 45 秒,ES 节点脱离集群。后来切到 G1GC 并限制 bulk 速率才解决。
G1GC 推荐配置:
-XX:+UseG1GC
-XX:MaxGCPauseMillis=200
-XX:G1HeapRegionSize=4m
-XX:InitiatingHeapOccupancyPercent=30
3. Thread Pool Rejected 数
ES 用线程池隔离不同操作。一旦线程池队列满了,后续请求会被 拒绝(rejected),客户端收到 429 Too Many Requests。
| 线程池 | 用途 | 告警条件 |
|---|---|---|
| write | 索引写入 | rejected > 0 |
| search | 搜索查询 | rejected > 0 |
| force_merge | 段合并 | rejected > 0 |
| management | 集群管理 | rejected > 0 |
查看方式:
GET /_cat/thread_pool?v&h=node_name,name,active,queue,rejected,type
踩坑案例:搜索线程池频繁 rejected,排查发现有人在 Kibana Dashboard 上设了 5 秒自动刷新,而 Dashboard 背后是 3 层嵌套聚合。高峰期 50 人同时开 Dashboard,搜索线程池被打爆。解决:Dashboard 刷新间隔改为 5 分钟,并加了缓存。
优化手段:
- 增大线程池队列:
thread_pool.search.queue_size: 1000 - 但更根本的是优化慢查询、限制并发
4. CPU 使用率和 Load
ES 吃 CPU 的场景:
- 写入高峰:Lucene 分词、构建倒排索引
- 复杂聚合:
terms、percentiles、cardinality - GC:频繁 GC 也会推高 CPU
| 指标 | 正常值 | 告警阈值 |
|---|---|---|
| CPU Usage | < 60% | > 80% 持续 5 分钟 |
| Load Average | < CPU 核数 | > CPU 核数 * 1.5 |
Load 高但 CPU 不高,通常是磁盘 IO 瓶颈导致进程在等 IO。
5. 磁盘 IO Util 和 Await
ES 对磁盘 IO 很敏感。IO Util > 80% 时写入和搜索都会明显变慢。
| 指标 | 正常值 | 告警阈值 |
|---|---|---|
| IO Util | < 40% | > 80% |
| Await(平均等待时间) | < 5ms(SSD) | > 20ms |
| IOPS | 越高越好 | 低于基线 50% |
踩坑案例:云服务器用的普通云盘,限速 300 IOPS。segment merge 期间 IO Util 飙到 100%,搜索延迟从 50ms 涨到 5s。核心原因:没有用 SSD。迁移到 ESSD 后问题消失。
6. 索引速率和搜索速率 QPS
| 指标 | 含义 | 查看方式 |
|---|---|---|
| Index Rate | 每秒索引文档数 | _cat/indices + 计算差值 |
| Search Rate | 每秒搜索次数(query + fetch) | _nodes/stats 的 search.query_total |
| Index Latency | 单次索引耗时 | _nodes/stats 的 indexing.index_time_in_millis / index_total |
| Search Latency | 单次搜索耗时 | _nodes/stats 的 search.query_time_in_millis / query_total |
7. _nodes/stats API 关键字段解读
GET /_nodes/stats
关键字段速查表:
| JSON Path | 含义 |
|---|---|
jvm.mem.heap_used_percent |
Heap 使用率 |
jvm.gc.collectors.old.collection_count |
Old GC 次数 |
thread_pool.write.rejected |
写入线程池拒绝数 |
thread_pool.search.rejected |
搜索线程池拒绝数 |
indices.search.query_total |
累计查询次数 |
indices.search.query_time_in_millis |
累计查询耗时 |
indices.indexing.index_total |
累计索引文档数 |
indices.indexing.index_time_in_millis |
累计索引耗时 |
fs.total.total_in_bytes / fs.total.free_in_bytes |
磁盘总量 / 剩余 |
os.cpu.percent |
CPU 使用率 |
8. 接入 Prometheus + Grafana 方案
架构
ES Node → elasticsearch_exporter → Prometheus → Grafana
步骤
Step 1:部署 elasticsearch_exporter
docker run -d \
--name es-exporter \
-p 9114:9114 \
quay.io/prometheuscommunity/elasticsearch-exporter:latest \
--es.uri=http://es-node:9200 \
--es.all \
--es.indices
Step 2:配置 Prometheus 抓取
# prometheus.yml
scrape_configs:
- job_name: 'elasticsearch'
static_configs:
- targets: ['localhost:9114']
scrape_interval: 30s
Step 3:导入 Grafana Dashboard
推荐使用 Grafana 官方模板 ID 2322(Elasticsearch Cluster Overview),导入后即可看到所有核心指标。
告警规则示例
# Prometheus alert rules
groups:
- name: elasticsearch
rules:
- alert: ESHeapUsageHigh
expr: elasticsearch_jvm_memory_used_bytes{area="heap"} / elasticsearch_jvm_memory_max_bytes{area="heap"} > 0.85
for: 5m
labels:
severity: warning
annotations:
summary: "ES Heap 使用率超过 85%"
- alert: ESThreadPoolRejected
expr: rate(elasticsearch_thread_pool_rejected_total{type="search"}[1m]) > 0
for: 1m
labels:
severity: critical
annotations:
summary: "ES 搜索线程池有拒绝"
- alert: ESOldGC
expr: rate(elasticsearch_jvm_gc_collection_seconds_count{gc="G1 Old Generation"}[5m]) > 0.1
for: 5m
labels:
severity: warning
annotations:
summary: "ES Old GC 过于频繁"
总结
| 层级 | 关注指标 | 工具 |
|---|---|---|
| 基础设施 | CPU、内存、磁盘 IO | node_exporter |
| JVM | Heap、GC、线程池 | elasticsearch_exporter |
| ES 业务 | QPS、延迟、rejected | elasticsearch_exporter |
| 可视化 | Dashboard、告警 | Grafana |
监控不是一次性搭建完就高枕无忧的:每接入一个新业务、每做一次大查询优化,都回头看看指标基线是否发生了变化,及时调整告警阈值。