集群变red的唯一原因是至少一个主分片未分配;需立即通过_cat/shards定位具体未分配主分片,结合unassigned.reason和_allocation/explain分析卡点,排查磁盘水位、节点离线或副本策略冲突等根本原因。

集群变 red 的核心原因只有一个:至少一个主分片(primary shard)未被分配。这不是配置漂移或监控误报,而是数据不可写、部分查询会失败的硬性故障。必须立刻定位哪个索引、哪个分片卡住了,而不是泛泛检查节点存活或磁盘空间。
查 unassigned_shards 具体是哪些分片
先看集群健康接口返回的 unassigned_shards 数值,再用以下命令列出所有未分配分片详情:
curl -s 'http://localhost:9200/_cat/shards?h=index,shard,prirep,state,unassigned.reason,node&v' | grep UNASSIGNED
关键字段说明:
-
prirep为p表示这是主分片 —— 只有这类分片未分配才会导致 red -
unassigned.reason是诊断起点,常见值包括:ALLOCATION_FAILED、CLUSTER_RECOVERED、INDEX_CREATED、NODE_LEFT、MANUAL_ALLOCATION - 如果 reason 是
NO_VALID_SHARD_COPY,说明所有副本都丢失或损坏,ES 找不到任何可用数据源来恢复该分片
确认是否因节点离线或磁盘水位触发分片拒绝
red 往往不是孤立事件,而是连锁反应。重点检查两件事:
- 执行
curl -s 'http://localhost:9200/_cat/nodes?v&h=ip,port,name,heap.percent,disk.used_percent',确认是否有节点disk.used_percent≥ 95% —— ES 默认会禁止向磁盘使用率超 95% 的节点分配分片(cluster.routing.allocation.disk.threshold_enabled默认 true) - 检查
_cat/nodes输出中是否缺失预期节点(比如本该 3 节点集群只看到 2 行),再查对应机器上的 ES 进程是否存活、日志里有没有NodeDisconnectedException或failed to join cluster - 若节点曾短暂离线又重连,但分片仍卡在
UNASSIGNED,很可能是分片元数据锁残留,需结合_cluster/allocation/explain深挖
用 _cluster/allocation/explain 定位具体卡点
对任意一个未分配的主分片,调用解释 API 获取 ES 内部决策逻辑:
curl -XPOST 'http://localhost:9200/_cluster/allocation/explain?pretty' -H 'Content-Type: application/json' -d '{
"index": "your_index_name",
"shard": 0,
"primary": true
}'
返回里重点关注:
-
can_allocate:是否允许分配(always/never/conditional) -
allocate_explanation:直接告诉你为什么不能分配,例如the node is above the high watermark或no known copy of the shard's data -
node_allocation_decisions下每个节点的decider判断,比如DiskThresholdDecider拒绝、SameShardAllocationDecider因副本策略阻止(如number_of_replicas: 2但只有 2 个节点,无法满足“主副不共节点”约束)
手动分配前必须确认数据一致性风险
不要一看到 unassigned 就急着 _cluster/reroute 强制分配。尤其当 explain 返回 NO_VALID_SHARD_COPY 时:
- 强制分配并启用
"accept_data_loss": true会导致该分片数据彻底清空 —— 索引里这部分文档永久丢失 - 如果该索引有快照(snapshot),优先走
_reindex从快照恢复;如果没有,且业务能容忍丢数据,才考虑强制分配 - 常见误操作:在单节点集群上把
number_of_replicas设为 1,结果 ES 死活不分配副本(因不允许主副同节点),却误以为是 red 故障,其实只是配置矛盾
真正棘手的 red 场景,往往藏在 explain 返回的 decider 链里 —— 比如磁盘水位、分片分配过滤器(cluster.routing.allocation.include)、甚至 JVM 内存不足导致 allocation service 停摆。这些不会直接报错,但会让分片永远卡在 unassigned。

















