ElasticsearchNotes

第 30 章:故障排查手册

zjc 于 2026-01-30 发布

这是《Elasticsearch 零基础实战指南》的独立章节版。本章从概念、实操和生产排查三个视角展开,代码块保留了原书可直接运行的版本。 本章按故障现象组织,给出确认命令、常见原因、处理步骤和预防动作。事故处理时先止血,再定位,最后复盘;不要在未确认影响面的情况下做大规模重建或重启。

30.1 通用排查流程

确认影响面
  -> 保存现场
  -> 判断集群/节点/索引/请求/链路
  -> 执行止血动作
  -> 根因定位
  -> 验证恢复
  -> 复盘改进

第一时间执行的命令:

GET /_cluster/health?timeout=5s
GET /_cat/nodes?v&h=name,node.role,master,heap.percent,cpu,disk.used_percent
GET /_cat/indices?v&health=red
GET /_cat/shards?v&h=index,shard,prirep,state,store,node,unassigned.reason
GET /_cluster/allocation/explain
GET /_cat/thread_pool/write,search?v&h=node_name,name,active,queue,rejected

保存现场:

GET /_cluster/state?filter_path=metadata,routing_table
GET /_nodes/stats?human
GET /_nodes/hot_threads
GET /_cat/pending_tasks?v

30.2 集群 Yellow

现象:主分片正常,部分副本未分配。

常见原因:

排查:

GET /_cluster/health?level=indices
GET /_cluster/allocation/explain
GET /_cat/allocation?v
GET /_cluster/settings?flat_settings=true

处理:

  1. 找到具体索引和分片;
  2. 阅读 allocation explain;
  3. 如果节点数不足,恢复节点或降低副本数;
  4. 如果磁盘水位高,清理或扩容;
  5. 如果 allocation 禁用,确认维护窗口后恢复;
  6. 如果过滤规则错误,修正 tier 或 attribute。

临时降低副本必须经过明确审批:

PUT logs-app/_settings
{
  "number_of_replicas": 0
}

30.3 集群 Red

现象:至少一个主分片不可用。

常见原因:

排查:

GET /_cat/indices?v&health=red
GET /_cat/shards?v&h=index,shard,prirep,state,store,node,unassigned.reason
GET /_cluster/allocation/explain

处理顺序:

  1. 确认是否所有节点在线;
  2. 恢复离线节点;
  3. 查看是否能从副本提升主分片;
  4. 查看磁盘水位;
  5. 查看 allocation enable;
  6. 必要时从快照恢复索引;
  7. 确认数据缺失影响面。

红线:

30.4 Unassigned Shard

定位原因:

GET /_cluster/allocation/explain

输出中的 allocate_explanationnode_allocation_deciders 通常会说明被哪个决策器阻止。

常见 decision:

原因 处理
disk watermark 清理或扩容
same shard conflict 增加数据节点
allocation disabled 恢复 allocation
tier mismatch 调整 tier preference 或节点属性
no node 恢复节点
shard failure 查看节点日志和损坏原因

重试分配:

POST /_cluster/reroute?retry_failed=true

这个命令只能重试已失败决策,不能解决磁盘满或节点不足等根因。

30.5 磁盘满

确认:

GET /_cat/allocation?v
GET /_nodes/stats/fs?human
GET /_cat/indices?v&h=index,store.size,pri.store.size

处理顺序:

  1. 暂停非必要导入和离线查询;
  2. 删除确认过期的索引;
  3. 缩短 ILM 保留期;
  4. 降低日志副本;
  5. 扩容磁盘或节点;
  6. 触发 reroute;
  7. 解除 read-only block。

查看 blocked 索引:

GET /_all/_settings?filter_path=*.settings.index.blocks.read_only_allow_delete

解除:

PUT /_all/_settings
{
  "index.blocks.read_only_allow_delete": null
}

只有先释放空间再解除,否则很快再次触发。

30.6 写入 429

现象:

EsRejectedExecutionException: rejected execution on write thread pool

排查:

GET /_cat/thread_pool/write?v&h=node_name,name,active,queue,rejected,completed
GET /_nodes/stats/indices/indexing,merge,refresh?human
GET /_cat/allocation?v

常见原因:

止血:

  1. 写入端限流;
  2. 指数退避;
  3. 暂停低优先级任务;
  4. 延长 refresh interval;
  5. 排查磁盘和节点热点。

客户端重试示例:

long delay = 500L;
for (int attempt = 0; attempt < 5; attempt++) {
    BulkResponse response = client.bulk(request);
    if (!response.hasFailures()) {
        return;
    }
    // 记录并只重试可重试 item,同时遵守退避
    Thread.sleep(delay);
    delay *= 2;
}

30.7 写入延迟高

排查路径:

检查项 命令
写入统计 GET index/_stats/indexing
合并压力 GET index/_stats/merges
刷新耗时 GET index/_stats/refresh
flush 耗时 GET index/_stats/flush
线程池 _cat/thread_pool/write
磁盘 _nodes/stats/fs
分片大小 _cat/shards

常见原因:

优先调整:

  1. 批量;
  2. refresh interval;
  3. 写入并发;
  4. 热点更新;
  5. 分片和磁盘容量。

30.8 查询慢

排查:

GET /_nodes/stats/indices/search,thread_pool?human
GET /_cat/thread_pool/search?v
GET products-v3/_stats/search?human

常见原因:

原因 特征
查询扇出大 涉及分片多,CPU 全节点升高
时间范围宽 日志类最常见
深分页 from+size 大
高基数聚合 heap 和 CPU 高
wildcard build_scorer 高
script collect/score 高
fetch 大 fetch phase 高
页缓存不足 磁盘 read 高
分片热点 个别节点负载高

止血:

  1. 取消当前搜索任务;
  2. 限制 Kibana 或分析端访问;
  3. 降低查询 QPS;
  4. 关闭明显错误的大查询;
  5. 必要时让索引 read-only 或隔离流量。

查看任务:

GET /_tasks?actions=*search*&detailed
POST /_tasks/TASK_ID/_cancel

30.9 JVM 高与熔断

确认:

GET /_nodes/stats/jvm,breaker?human
GET /_nodes/hot_threads

常见原因:

止血:

  1. 取消大查询;
  2. 限制聚合和分页;
  3. 关闭相关 Dashboard;
  4. 必要时滚动重启前先切流;
  5. 确认恢复后再放流量。

不要只根据 heap 使用率重启。先看 GC 是否能回收、 breaker 类型、当前任务和 hot threads。

30.10 Master 不稳定

现象:

排查:

GET /_cluster/health?explain=true
GET /_cat/pending_tasks?v
GET /_nodes/hot_threads
GET /_cat/nodes?v&h=name,node.role,master,cpu,load_average,heap.percent

常见原因:

处理:

  1. 恢复 master-eligible 节点数量;
  2. 降低 cluster state 规模;
  3. 清理无用索引和模板;
  4. 分离 master 节点;
  5. 排查网络和 GC;
  6. 控制索引创建频率。

30.11 副本恢复慢

查看:

GET /_cat/recovery?v&active_only=true
GET /_cat/shards?v&h=index,shard,prirep,state,store,node

常见限制:

调整恢复速度要谨慎:

PUT /_cluster/settings
{
  "persistent": {
    "indices.recovery.max_bytes_per_sec": "100mb"
  }
}

恢复期间业务影响:

30.12 数据不一致或丢失

先确认问题类型:

现象 可能原因
查不到最新数据 refresh 未发生
主库有但 ES 没有 同步链路断
ES 有重复数据 幂等缺失
字段缺失 Mapping/dynamic 策略
数值统计不对 指标口径或近似聚合
索引被删 权限或误操作
节点数据损坏 磁盘故障

排查顺序:

  1. 按业务 ID 点查;
  2. 检查 _source 与主库差异;
  3. 查看同步任务 offset;
  4. 查看 Kafka lag 和死信;
  5. 检查 bulk item 错误;
  6. 检查 Mapping 和 pipeline;
  7. 检查最近变更和审计日志;
  8. 必要时按 ID 重放。

不要把 ES 当主数据源。恢复顺序应以数据库、消息系统或快照为准。

30.13 滚动重启

滚动重启前:

  1. 确认集群 green 或明确当前风险;
  2. 暂停索引分配;
  3. 确认快照可恢复;
  4. 记录分片分布;
  5. 通知写入方准备重试;
  6. 一次只重启一个节点。

暂停分配:

PUT /_cluster/settings
{
  "persistent": {
    "cluster.routing.allocation.enable": "primaries"
  }
}

节点恢复并加入后,再恢复:

PUT /_cluster/settings
{
  "persistent": {
    "cluster.routing.allocation.enable": null
  }
}

如果使用 none,必须确保维护过程没有索引创建或节点二次故障。

30.14 事故复盘模板

事故时间:
发现时间:
恢复时间:
影响范围:
业务指标:
时间线:
根因:
 contributing factors:
止血动作:
长期改进:
责任人:
截止时间:
验证方式:

复盘重点不是处罚,而是补齐四件事:监控、自动化、权限和演练。

本章小结

故障排查要先判断影响面和资源层级,再使用 health、allocation explain、stats、thread pool、tasks 和 hot threads 定位。集群问题时看分片与水位,写入问题时看 bulk、merge、translog 和磁盘,查询问题时看扇出、分页、聚合、缓存和 fetch。

思考题

  1. yellow 和 red 的第一步排查有什么不同?
  2. 磁盘 flood stage 解锁前必须先做什么?
  3. 为什么 429 出现时不建议先加大线程池队列?
  4. 如何区分“数据没写入”和“数据写入但不可见”?
  5. 滚动重启时为什么要控制 allocation?