直接查 _cat/shards 并过滤 unassigned 可快速定位未分配分片及粗略原因(如 node_left、replica_added);若 unassigned.reason 为空或需精确诊断,则调用 _cluster/allocation/explain 查看 can_allocate、allocate_explanation 和 node_allocation_decisions 获取根本原因。

怎么快速定位哪些分片处于 UNASSIGNED 状态
直接查 _cat/shards 是最轻量、最常用的第一步。它能立刻告诉你「谁没分配」,以及「为什么没分配」的粗略线索。
执行命令:
curl -XGET "http://localhost:9200/_cat/shards?v&h=index,shard,prirep,state,unassigned.reason&s=state" | grep UNASSIGNED
重点关注输出中的 unassigned.reason 列,比如 NODE_LEFT、ALLOCATION_FAILED、REPLICA_ADDED —— 这些就是 ES 官方定义的 12 种未分配原因里的具体值,已经能排除掉一半以上常见场景。
- 如果全是
REPLICA_ADDED,大概率是刚调大了副本数,但节点数不够(单节点集群必现) - 如果出现多个
NODE_LEFT,说明有节点失联过,且主分片或副本没及时恢复 - 如果
unassigned.reason为空或显示NULL,说明问题更底层,得进下一步深挖
用 allocation/explain 精确诊断分配失败原因
_cluster/allocation/explain 是唯一能告诉你「为什么不能分配」的 API。它不猜、不推测,直接模拟分配逻辑,逐节点给出拒绝理由。
有两种用法:
- 查任意一个未分配分片:
curl -XGET "http://localhost:9200/_cluster/allocation/explain?pretty" -H 'Content-Type: application/json' -d '{"index":"my_index","shard":0,"primary":false}' - 查集群里第一个卡住的分片(省得指定参数):
curl -XGET "http://localhost:9200/_cluster/allocation/explain?pretty"
关键看返回里的三个字段:
-
can_allocate:值为no或no_valid_shard_copy就别绕弯子了,说明真没地方放 -
allocate_explanation:人类可读的失败原因,比如"the shard cannot be allocated to the same node on which a copy of the shard already exists"—— 这就是单节点副本无法分配的铁证 -
node_allocation_decisions数组:列出每个节点的判决细节,其中deciders里会标明哪个策略拦住了它,比如same_shard、disk_threshold、enable
常见原因对应的关键配置和检查点
很多 unassigned 分片不是 bug,而是被显式策略拦住的。以下几项配置一旦设错,分片就永远卡在 UNASSIGNED:
-
cluster.routing.allocation.enable:设成none会彻底禁用所有分片分配(包括新建索引),检查命令:curl -XGET http://localhost:9200/_cluster/settings?include_defaults=true | grep enable -
cluster.routing.allocation.disk.threshold_enabled:默认开启,若某节点磁盘 usage > 85%,该节点将拒绝接收新分片;查磁盘水位:curl -XGET http://localhost:9200/_cat/allocation?v -
index.routing.allocation.total_shards_per_node:单节点最多承载多少分片(含主+副本),超限后新分片直接 unassigned;查索引设置:curl -XGET http://localhost:9200/my_index/_settings?pretty -
cluster.routing.allocation.exclude._ip或include:可能把所有节点都 exclude 掉了,导致无节点可选
这些配置改起来快,但容易被忽略——尤其在做过集群迁移或磁盘扩容后忘记调高水位线。
主分片丢失或副本陈旧时的特殊处理
当 allocation/explain 返回 "can_allocate":"no_valid_shard_copy",说明集群找不到一份「in-sync」的分片副本。这时不能硬 reroute,得先确认数据是否真的丢了:
- 如果是主分片丢失(
primary:true+no_valid_shard_copy),且你确定数据不可恢复,只能强制分配陈旧副本:curl -XPOST "http://localhost:9200/_cluster/reroute?pretty" -H 'Content-Type: application/json' -d '{ "commands": [ { "allocate_stale_primary": { "index": "my_index", "shard": 0, "node": "data-node-1", "accept_data_loss": true } } ] }' - 注意
accept_data_loss:true是必须参数,ES 不会让你误操作;执行前务必确认该分片近期无写入,否则会丢数据 - 如果只是副本陈旧(
primary:false),通常等主分片恢复后会自动同步;强行 allocate_stale_primary 仅用于极端故障恢复,日常应优先排查节点网络与磁盘健康
真正难处理的,永远不是报错信息本身,而是解释里那句 "cannot allocate because all found copies of the shard are either stale or corrupt"——它意味着你得在「丢数据」和「停服务」之间做选择,而这个选择,没有 API 能帮你做。











