4、集群健康诊断:掌握Elasticsearch集群健康状态(绿/黄/红)的含义,学习分片分配、节点故障的诊断方法。

说实话,我见过太多团队,ES集群一报警就慌。看到状态变黄就重启,看到变红就重建索引。其实没必要。你只要搞懂那三种颜色到底在说什么,大部分问题都能自己搞定。

今天我们就聊聊集群健康诊断。我会把绿、黄、红的含义讲透,再分享一些我实战中总结的分片分配和节点故障排查方法。

4.1 集群健康状态:绿、黄、红到底代表什么?

ES集群的健康状态,说白了就是看所有主分片和副本分片是否都到位了。它只有三种颜色:绿、黄、红。

状态 含义 是否可用 常见原因
绿色 所有主分片和副本分片都已分配 完全可用 正常状态
黄色 所有主分片已分配,但部分副本未分配 可用,但有风险 节点数不足、磁盘空间不足、副本配置问题
红色 至少一个主分片未分配 部分数据不可用 节点宕机、磁盘故障、分片损坏

你可能会问:黄色状态到底要不要管?我个人习惯是,如果只是短暂出现,比如集群在滚动重启,那可以等。但如果持续超过几分钟,就得查了。我曾经遇到过一个案例,黄色状态持续了一周,结果一个节点挂了,数据直接丢了——因为副本根本没到位。

4.2 如何查看集群健康状态?

最直接的方式就是调用API:

GET _cluster/health

返回结果长这样:

{
  "cluster_name" : "my_cluster",
  "status" : "yellow",
  "timed_out" : false,
  "number_of_nodes" : 3,
  "number_of_data_nodes" : 3,
  "active_primary_shards" : 120,
  "active_shards" : 180,
  "relocating_shards" : 0,
  "initializing_shards" : 0,
  "unassigned_shards" : 60,
  "delayed_unassigned_shards" : 0,
  "number_of_pending_tasks" : 0,
  "number_of_in_flight_fetch" : 0,
  "task_max_waiting_in_queue_millis" : 0,
  "active_shards_percent_as_number" : 75.0
}

这里有个关键字段:unassigned_shards。如果这个值大于0,说明有分片没分配。黄色状态下,没分配的都是副本;红色状态下,没分配的有主分片。

我的小技巧: 我习惯写一个脚本,每分钟检查一次 unassigned_shardsactive_shards_percent_as_number。一旦发现未分配分片数超过阈值,或者活跃分片占比低于99%,就自动告警。这比等用户报错要快得多。

4.3 分片分配问题诊断

分片分配问题,是集群健康问题的核心。说白了,就是ES不知道该把分片放哪,或者放不上去。

4.3.1 查看未分配分片的原因

先找到哪些分片没分配:

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

返回结果中,unassigned.reason 字段会告诉你原因。常见的有:

  • INDEX_CREATED:索引刚创建,分片正在分配中
  • CLUSTER_RECOVERED:集群恢复中
  • NODE_LEFT:节点离开集群,分片需要重新分配
  • REPLICA_ADDED:新增副本,正在分配
  • ALLOCATION_FAILED:分配失败,需要进一步排查
  • REROUTE_CANCELLED:重新路由被取消

嗯,这里要注意:ALLOCATION_FAILED 是最棘手的。我曾经遇到过,原因是磁盘空间不足,但ES的分配器没正确识别。最后手动清理了磁盘才解决。

4.3.2 深入排查分配失败

如果看到 ALLOCATION_FAILED,可以用这个API看详细错误:

GET _cluster/allocation/explain?pretty

返回结果会告诉你为什么分配失败,比如:

{
  "index" : "my_index",
  "shard" : 0,
  "primary" : true,
  "current_state" : "unassigned",
  "unassigned_info" : {
    "reason" : "ALLOCATION_FAILED",
    "details" : "failed to allocate, failure message: [shard] creation of shard [my_index][0] failed on node [node-1]"
  },
  "can_allocate" : "no",
  "allocate_explanation" : "cannot allocate because allocation is not permitted to any of the nodes",
  "node_allocation_decisions" : [
    {
      "node_id" : "node-1",
      "node_name" : "node-1",
      "deciders" : [
        {
          "decider" : "disk_threshold",
          "decision" : "NO",
          "explanation" : "the node has insufficient disk space"
        }
      ]
    }
  ]
}

你看,这里明确说了是磁盘空间不足。所以排查时,先看这个API,能省很多时间。

避坑指南: 我曾经遇到过一个问题:_cluster/allocation/explain 返回的是 "no allocations",但磁盘明明还有空间。后来发现是ES的磁盘水位线配置有问题。检查一下 cluster.routing.allocation.disk.watermark.lowhigh 这两个参数,默认是85%和90%。如果你的磁盘使用率刚好卡在阈值附近,就会出现这种诡异情况。

4.4 节点故障诊断

节点故障,是导致集群变红的最常见原因。一个节点挂了,它上面的主分片就会变成未分配状态。

4.4.1 检查节点状态

先看看集群里还有哪些节点活着:

GET _cat/nodes?v

重点关注 node.rolemaster 字段。如果某个数据节点消失了,那它上面的分片就需要重新分配。

我习惯用这个命令快速定位问题节点:

GET _cat/nodes?v&h=name,node.role,master,heap.percent,ram.percent,cpu,load_1m,disk.used_percent

这样能一眼看出哪个节点的资源使用率异常。比如CPU飙到100%,或者磁盘快满了,那这个节点很可能就是罪魁祸首。

4.4.2 节点宕机后的恢复流程

当一个节点宕机,ES会做这几件事:

  1. 检测到节点离开集群(默认30秒超时)
  2. 将该节点上的主分片标记为未分配
  3. 集群状态变为红色(如果有主分片丢失)
  4. 开始在其他节点上分配这些主分片
  5. 主分片分配完成后,再分配对应的副本
  6. 集群状态恢复为绿色(如果所有分片都分配成功)

你想想看,这个过程需要时间。如果节点只是短暂重启,ES可能会等一段时间再重新分配。这个等待时间由 index.unassigned.node_left.delayed_timeout 控制,默认是5分钟。

我的建议: 如果你的节点经常重启(比如做运维操作),可以把延迟时间设长一点,比如30分钟。这样节点重启回来后,分片还在原地,不用重新分配,速度会快很多。设置方式:PUT _all/_settings {"settings": {"index.unassigned.node_left.delayed_timeout": "30m"}}

4.4.3 手动重新分配分片

有时候ES的自动分配不够智能,或者你想手动干预。可以用 _cluster/reroute API:

POST _cluster/reroute
{
  "commands": [
    {
      "allocate_stale_primary": {
        "index": "my_index",
        "shard": 0,
        "node": "node-2",
        "accept_data_loss": true
      }
    }
  ]
}

这个命令会把一个未分配的主分片分配到指定节点。注意 accept_data_loss 参数,它表示你接受可能的数据丢失。因为那个分片可能已经损坏了。

警告: 手动重新分配分片是最后的手段。我一般只在自动分配完全失败,或者集群处于紧急状态时才用。而且一定要先确认目标节点有足够的磁盘空间和资源。我曾经手滑把一个分片分配到了磁盘快满的节点上,结果那个节点直接挂了,连锁反应导致整个集群瘫痪。

4.5 实战:一个典型的红色集群恢复过程

我记得有一次,凌晨三点被报警吵醒。集群状态变红了。我按这个步骤排查:

  1. 先看健康状态GET _cluster/health,确认是红色,unassigned_shards 是12
  2. 找未分配分片GET _cat/shards?v&h=index,shard,prirep,state,node,unassigned.reason,发现有两个主分片未分配,原因是 NODE_LEFT
  3. 查节点状态GET _cat/nodes?v,发现少了一个数据节点
  4. 看分配解释GET _cluster/allocation/explain,发现是因为剩余节点磁盘空间不足,无法分配
  5. 临时解决:清理了一个节点的磁盘,然后手动触发重新分配:POST _cluster/reroute?retry_failed=true
  6. 恢复:几分钟后,集群变回绿色

整个过程大概15分钟。如果当时慌了,直接重启集群,可能反而会出更多问题。

4.6 总结

集群健康诊断,说白了就是三件事:看颜色、找原因、动手修。绿色不用管,黄色查副本,红色查主分片。记住这几个API,大部分问题都能搞定:

  • _cluster/health:看整体状态
  • _cat/shards:看分片分布
  • _cluster/allocation/explain:看分配失败原因
  • _cat/nodes:看节点状态
  • _cluster/reroute:手动干预

嗯,今天就聊到这。下一章我们会讲如何用监控工具实时跟踪这些指标,到时候再分享一些我自己的监控面板配置经验。