1. 概述

Elasticsearch 通过 分片(Shards) 将数据分布在整个集群的多个节点上。分片是实现可扩展性的关键机制,同时也能提升查询和写入性能。但当某些分片处于未分配状态时,会带来什么影响?我们又该如何诊断和修复这类问题?

本文将介绍什么是未分配分片,它们产生的原因、对集群的影响,并提供多种排查和解决方法。

文中所有命令均假设在 Elasticsearch 部署节点上运行,默认端口为 9200

2. 什么是未分配分片?

简单来说,未分配分片(Unassigned Shard)是指尚未分配到任何节点的分片。这意味着这部分数据暂时无法被访问,无论是搜索还是写入操作都会受到影响。

2.1 分片为何会未分配?

常见的原因包括:

  • 节点宕机或不可达:节点宕机后,其上的分片会变成未分配状态,直到 Elasticsearch 重新分配这些分片。
  • 集群重新平衡:当集群节点之间分片分布不均时,Elasticsearch 会尝试重新分配,部分分片可能在此过程中短暂处于未分配状态。
  • 磁盘空间不足:当某个节点磁盘快满时,Elasticsearch 会拒绝将新分片分配到该节点,导致已分配分片变为未分配。

2.2 未分配分片对集群的影响

  • ✅ 数据不可访问,搜索结果可能不完整。
  • ✅ 写入操作可能失败或被阻塞。
  • ✅ 集群会尝试重新分配分片,可能造成额外负载,影响整体性能。

3. 诊断未分配分片

Elasticsearch 提供了多个 API 帮助我们快速识别未分配分片。

3.1 _cat/shards API

使用该 API 可以快速查看所有分片的状态:

$ curl -X GET "localhost:9200/_cat/shards?v"
index                                                         shard prirep state      docs  store dataset ip        node
customers_v2                                                  0     p      STARTED      10  7.9kb   7.9kb 127.0.0.1 node-1
products_new                                                  0     p      STARTED       2  5.5kb   5.5kb 127.0.0.1 node-1
test-index                                                    0     p      UNASSIGNED                               
test-index                                                    1     p      UNASSIGNED                               
test-index                                                    2     p      UNASSIGNED                               
products_old                                                  0     p      STARTED       2  5.2kb   5.2kb 127.0.0.1 node-1

⚠️ 上例中 test-index 的三个分片状态为 UNASSIGNED,即为未分配分片。

3.2 _cluster/health API

该 API 提供集群健康状态,包括未分配分片数量:

$ curl -X GET "localhost:9200/_cluster/health?pretty"
{
  "cluster_name" : "my-cluster",
  "status" : "red",
  "timed_out" : false,
  "number_of_nodes" : 1,
  "number_of_data_nodes" : 1,
  "active_primary_shards" : 8,
  "active_shards" : 8,
  "relocating_shards" : 0,
  "initializing_shards" : 0,
  "unassigned_shards" : 3,
  "delayed_unassigned_shards" : 0,
  ...
}

⚠️ 当 unassigned_shards 大于 0 且集群状态为 red 或 yellow 时,说明存在未分配分片。

4. 解决未分配分片问题

4.1 重启故障节点

如果未分配分片是由于节点宕机引起的,第一步应尝试重启该节点。节点恢复后,Elasticsearch 会自动尝试重新分配相关分片。

✅ 检查集群状态和分片分配状态,确认是否已自动恢复。

4.2 手动分配分片

在某些情况下,需要使用 _cluster/reroute API 手动分配分片。如果是主分片,使用 allocate_empty_primary 命令:

$ curl -XPOST 'localhost:9200/_cluster/reroute' -H 'Content-Type: application/json' -d '{
    "commands": [{
        "allocate_empty_primary": {
            "index": "test-index",
            "shard": 1,
            "node": "node-1",
            "accept_data_loss": true
        }
    }]
}'

⚠️ 使用 accept_data_loss: true 表示接受可能的数据丢失风险。

✅ 替换以下字段即可复用该命令:

  • test-index ➜ 实际索引名
  • 1 ➜ 分片编号
  • node-1 ➜ 目标节点名

如果是因为磁盘空间不足导致分片未分配,可设置索引分配策略,确保分片分配到有足够空间的节点:

$ curl -X PUT "http://localhost:9200/test_index/_settings" \
-H 'Content-Type: application/json' \
-d '{ "index.routing.allocation.require._tag": "data_node" }'

✅ 该配置确保分片仅分配到带有 data_node 标签的节点。

4.3 调整集群设置

Elasticsearch 提供了多个集群级设置用于优化分片分配:

  • ✅ 启用分片分配(默认为 all):
$ curl -X PUT "localhost:9200/_cluster/settings" -H 'Content-Type: application/json' -d'
{
  "persistent": {
    "cluster.routing.allocation.enable": null
  }
}'
  • ✅ 增加节点并发恢复数量,加快分片恢复速度:
$ curl -X PUT "localhost:9200/_cluster/settings" -H 'Content-Type: application/json' -d'
{
  "persistent": {
    "cluster.routing.allocation.node_concurrent_recoveries": 5
  }
}'

✅ 该设置允许每个节点同时恢复 5 个分片,适用于分片恢复高峰期。

4.4 设置副本数量

为减少因节点宕机导致的未分配分片,可设置合理的副本数量:

$ curl -X PUT "localhost:9200/test-index" -H 'Content-Type: application/json' -d'
{
  "settings": {
    "index.number_of_replicas": 2
  }
}'

⚠️ 注意:如果集群节点数不足以容纳所有副本,Elasticsearch 会将多余副本标记为未分配。例如,设置 2 个副本时,至少需要 3 个节点才能完全分配主分片和副本。

5. 总结

本文介绍了 Elasticsearch 中未分配分片的原因、诊断方法和修复策略:

  • ✅ 通过 _cat/shards_cluster/health API 快速识别问题。
  • ✅ 重启节点、手动分配分片、调整集群设置等方法可有效解决未分配问题。
  • ✅ 设置合理副本数、分配策略有助于预防未分配分片。

⚠️ 在实际运维中,建议定期监控集群状态,及时发现并处理未分配分片,避免影响服务稳定性。


原始标题:How to Assign Unassigned Shards in Elasticsearch