4. 集群健康与故障检测

Elasticsearch 的集群健康状态是运维人员最先接触、也最容易被误读的指标。它只有三个取值:green、yellow、red,但三者背后对应的是分片分配状态的不同组合,而不是集群整体性能的好坏。理解判定逻辑,才能避免"看到 yellow 就重启集群"这类危险操作。

一、健康状态的判定逻辑

集群健康由主节点根据主分片(primary shard)和副本分片(replica shard)的分配情况计算得出,判定规则非常明确:

  • green:所有索引的主分片和副本分片都已成功分配到节点上,集群功能完整。
  • yellow:所有主分片均已分配,但至少有一个副本分片未分配。数据可读可写,但缺少冗余,节点故障时存在数据丢失风险。
  • red:至少有一个主分片未分配,对应索引的部分数据不可读写,属于严重故障。

需要注意,健康状态是集群级别的聚合结果,取所有索引中最差的状态。只要有一个索引是 red,整个集群就是 red。因此排查时不能只看集群状态,必须下钻到索引和分片级别。

查看集群健康:GET _cluster/health,返回 status、number_of_nodes、active_primary_shards、active_shards、unassigned_shards 等字段。
查看索引级健康:GET _cluster/health?level=indices。
查看分片级详情:GET _cat/shards?v&h=index,shard,prirep,state,unassigned.reason。

二、故障检测机制

Elasticsearch 的故障检测依赖两层心跳:主节点与数据节点之间的心跳,以及节点之间的故障探测。核心参数是 cluster.fault_detection.leader_check.interval(默认 1s)和 cluster.fault_detection.follower_check.interval(默认 1s)。

主节点会周期性向所有节点发送 leader check,若连续多次未收到响应,则判定该节点失联,将其从集群状态中移除,并触发分片重新分配。默认情况下,节点失联判定阈值约为 30 秒(由 cluster.fault_detection.leader_check.timeout 与重试次数共同决定)。

节点失联后,主节点会执行以下动作:

  1. 将该节点标记为不可用,从集群状态中移除。
  2. 该节点上的主分片被标记为未分配,触发主分片重新选举或提升副本。
  3. 若存在可用副本,副本被提升为主分片,集群状态可能从 green 变为 yellow。
  4. 若没有可用副本,主分片保持未分配,集群变为 red。

三、节点失联与恢复流程

节点恢复上线后,会重新加入集群。此时主节点会检查该节点上的分片数据是否与当前主分片一致:若一致,直接作为副本加入;若落后,则通过分片恢复(peer recovery)从主分片同步差异数据。恢复期间,分片状态为 INIT 或 RELOCATING,可通过 GET _cat/recovery?v 观察进度。

恢复完成后,副本分片重新分配,集群健康状态回到 green。若恢复过程中再次发生节点失联,主节点会重新触发分配,可能造成反复恢复,此时应检查网络稳定性和 cluster.routing.allocation 相关配置。

集群健康判定与节点失联恢复流程 健康状态判定 green:主+副本全部分配 yellow:主分配,副本缺失 red:存在未分配主分片 故障检测机制 leader_check 心跳(默认 1s) 连续超时 → 判定节点失联 移除节点 → 触发分片重分配 节点恢复流程 节点重新加入集群 校验分片数据一致性 peer recovery 同步差异 节点失联后的状态流转与结果判读 green 主+副本正常 yellow 副本缺失,可读写 red 主分片未分配 恢复中 INIT / RELOCATING 副本丢失 无副本可提升 节点回归 peer recovery 完成后副本补齐,状态回到 green 排查入口:GET _cluster/health?level=indices → GET _cat/shards?v → GET _cat/recovery?v → GET _cluster/allocation/explain

四、常见健康问题的排查方法

场景一:yellow 且 unassigned_shards 长期不降。常见原因是副本数大于可用节点数,或节点被分配过滤规则排除。排查步骤:

GET _cluster/allocation/explain
{
  "index": "logs-2024",
  "shard": 0,
  "primary": false
}

返回结果中的 unassigned_info.reason 会直接说明原因,例如 NODE_LEFT、ALLOCATION_FAILED、CLUSTER_RECOVERED。若为 NODE_LEFT 且节点已恢复,通常等待自动分配即可;若为 ALLOCATION_FAILED,需检查磁盘水位、分片大小和 index.routing.allocation 设置。

场景二:red 且主分片未分配。这是最严重的情况。首先确认该主分片是否有可用副本:

GET _cat/shards/logs-2024?v&h=index,shard,prirep,state,node,unassigned.reason

若存在 STARTED 的副本,主节点会自动提升其为主分片,集群恢复为 yellow。若所有副本均不可用,则只能等待原节点回归,或使用 POST _cluster/reroute 手动分配。手动分配前必须确认目标节点上存在该分片的完整数据,否则会造成数据丢失。

不要轻易使用 allocate_empty_primary 强制分配空主分片,这会导致该分片上的历史数据永久丢失。仅在确认数据可丢弃时使用。

场景三:节点频繁失联。若日志中反复出现 master_left 或 node_left,应检查网络延迟、GC 停顿和 cluster.fault_detection 参数。对于跨机房部署,可适当调大 leader_check.timeout,避免因短暂网络抖动误判失联。

五、排查清单

现象优先检查常用命令
yellow 持续副本数 vs 节点数、分配过滤规则_cluster/allocation/explain
red 主分片未分配是否有可用副本、节点是否回归_cat/shards
节点频繁失联网络延迟、GC、心跳超时_cat/nodes?v、节点日志
恢复缓慢恢复限流、磁盘 IO_cat/recovery?v