天天看点

[unassigned_shards]Fix issue: elasticsearch unassigned shards

今天遇到了一个elasticsearch相关的坑[unassigned shards],蹚完了,记录一下(详细的解释在中下方,耐心看完)。

1.先确保elasticsearch(后简称es)处于启动状态; 

/etc/init.d/elasticsearch start
#查看9200端口是否正常 [netstat -tnlp | grep 9200] 
           

2.查看集群状态信息和状态为unassigned_shards的分片信息

#查看集群状态
curl -XGET 'http://localhost:9200/_cluster/health?pretty'
发现status是红色的,且存在unassigned_shards信息(图略)
#查看状态为unassigned的分片信息
curl -XGET 'http://localhost:9200/_cat/shards' | grep UNASSIGNED
           

3.查看节点名称并执行强制的reroute

#查看节点的名称
curl -XGET 'http://localhost:9200/_nodes/stats?pretty
#强制reroute的格式
curl -XPOST 'localhost:9200/_cluster/reroute' -d '{

        "commands" : [ {

              "allocate" : {

                  "index" : "test",

                  "shard" : 4,

                  "node" : "es-node1",

                  "allow_primary" : true

              }

            }

        ]

    }'"
index为要处理的索引名称,shard代表要处理的分配序号,node代表节点名称。
           

再查看集群状态就恢复成green了。

下面是批量处理未注册的shard信息的方法:脚本如下:

#!/bin/bash
for index in $(curl  -s 'http://localhost:9200/_cat/shards' | grep UNASSIGNED | awk '{print $1}' | sort | uniq); do
    for shard in $(curl  -s 'http://localhost:9200/_cat/shards' | grep UNASSIGNED | grep $index | awk '{print $2}' | sort | uniq); do
        echo  $index $shard
        curl -XPOST 'localhost:9200/_cluster/reroute' -d "{
            'commands' : [ {
                  'allocate' : {
                      'index' : $index,
                      'shard' : $shard,
                      'node' : 'es-node1',
                      'allow_primary' : true
                  }
                }
            ]
        }"
        sleep 5
    done
done
#其中的node对应的值为自己节点的名称
           

如果这还未解决,就耐心继续向下看,应该会有所帮助:

当看到unassigned shards,验证未分配的分片是否包含我们需要保留的数据(如果不是,删除这些分片是解决问题的最直接方法)。 如果您已经知道数据是有价值的,且上述方式不行,继续参照下面的几个解决方案解决问题:

1.分片分配被故意延迟
2.分片过多,节点不足
3.需要重新启用分片分配
4.分片数据不再存在于集群中
5.低磁盘水印
6.多个es版本
           

原因1:分片分配被故意延迟

当节点离开集群时,主节点会临时延迟分片重新分配,以避免不必要的资源浪费在重新平衡分片上,以防原始节点能够在一定时间段内恢复(默认为一分钟)。 在这种情况下,您的日志应如下所示:

[TIMESTAMP][INFO][cluster.routing] [MASTER NODE NAME] delaying allocation for [54] unassigned shards, next check in [1m]
           

动态修改延迟时间:

curl -XPUT 'localhost:9200/<INDEX_NAME>/_settings' -d 
'{
	"settings": {
	   "index.unassigned.node_left.delayed_timeout": "30s"
	}
}'
           

用_all替换<INDEX_NAME>将更新集群中所有索引的阈值。

延迟期结束后,您应该开始看到主站分配这些分片。 如果不是,下一站[问题2]。

原因2:分片过多,节点不足

当节点加入并离开集群时,主节点会自动重新分配分片,以确保没有将分片的多个副本分配给同一节点。 换句话说,主节点不会将主分片与其副本分配给同一节点,也不会将同一分片的两个副本分配给同一节点。 如果没有足够的节点来相应地分配分片,则分片可能会停留在未分配状态。为避免出现此问题,请遵循以下公式,确保初始化集群中的每个索引时,每个主分片的副本数少于集群中节点的数量:

N >= R + 1
#N是群集中节点的数量,R是群集中所有索引中最大的碎片复制因子。
           

在下面的截图中,多碎片索引存储在四个主碎片上,每个主碎片都有四个副本。 索引的20个分片中有8个未分配,因为我们的集群仅包含三个节点。尚未分配每个主要分片的两个副本,因为三个节点中的每个节点已经包含该分片的副本。

[unassigned_shards]Fix issue: elasticsearch unassigned shards

要解决此问题,可以将更多数据节点添加到群集,也可以减少副本数。 在我们的示例中,我们要么需要在集群中添加至少两个以上的节点,要么将复制因子减少为两个,如下所示:

curl -XPUT 'localhost:9200/<INDEX_NAME>/_settings' -d '{"number_of_replicas": 2}'
#减少副本数后,查看Kopf以查看是否已分配所有分片。
           

还不行吗?继续下一个[问题3]

原因3:需要重新启用分片分配

在下面的Kopf屏幕截图中,一个节点刚刚加入集群,但是尚未分配任何分片。

[unassigned_shards]Fix issue: elasticsearch unassigned shards

默认情况下,所有节点上都启用了分片分配,但是您可能在某个时候禁用了分片分配(例如,为了执行滚动重启),而忘记了重新启用它。

要启用分片分配,请更新“群集设置” API:

curl -XPUT 'localhost:9200/_cluster/settings' -d
'{ "transient":
    { "cluster.routing.allocation.enable" : "all" 
    }
}'
           

如果这解决了问题,则Kopf或Datadog仪表板应显示未分配的碎片数在成功分配给节点后减少。

[unassigned_shards]Fix issue: elasticsearch unassigned shards
[unassigned_shards]Fix issue: elasticsearch unassigned shards

看起来这解决了我们所有未分配分片的问题,只有一个例外:constant-updates索引的分片0。让我们探究为何未分配分片的其他可能原因。

原因4:分片数据不再存在于集群中

在这种情况下,常量更新索引的主分片0未分配。它可能是在没有任何副本的节点上创建的(一种用于加快初始索引过程的技术),并且该节点在可以复制数据之前离开了群集。主服务器在其全局集群状态文件中检测到分片,但无法在集群中找到分片的数据。

另一种可能性是节点在重新引导时可能遇到了问题。通常,当节点恢复与群集的连接时,它会将有关其磁盘碎片的信息中继到主节点,然后由主节点将这些碎片从“未分配”转换为“已分配/启动”。如果此过程由于某种原因而失败(例如,节点的存储已以某种方式损坏),则碎片可能仍未分配。

在这种情况下,您必须决定如何进行:尝试使原始节点恢复并重新加入集群(并且不强制分配主分片),或者使用Reroute API强制分配分片并使用以下方法重新索引丢失的数据原始数据源,或来自备份。

如果您决定分配一个未分配的主分片,请确保在请求中添加“ allow_primary”:“ true”标志:

curl -XPOST 'localhost:9200/_cluster/reroute' -d 
'{ "commands" :
      [ { "allocate" : 
          { "index" : "constant-updates", "shard" : 0, "node": "<NODE_NAME>", "allow_primary": "true" }
      }]
}'
           

没有“ allow_primary”:“ true”标志,我们将遇到以下错误:

{"error":{"root_cause":[{"type":"remote_transport_exception","reason":"[NODE_NAME][127.0.0.1:9301][cluster:admin/reroute]"}],"type":"illegal_argument_exception","reason":"[allocate] trying to allocate a primary shard [constant-updates][0], which is disabled"},"status":400}
           

强制分配主分片的警告是,您将分配“空”分片。如果包含原始主分片数据的节点稍后要重新加入集群,则其数据将被新创建的(空)主分片覆盖,因为它将被视为数据的“更新”版本。

现在,您将需要重新索引丢失的数据,或者使用Snapshot and Restore API从备份快照中进行尽可能多的还原。

原因5:低磁盘水印

如果没有足够的节点具有足够的磁盘空间,则主节点可能无法分配分片(它不会将分片分配给磁盘使用率超过85%的节点)。一旦节点达到此磁盘使用水平,或被Elasticsearch称为“磁盘低水位标记”,就不会为它分配更多的分片。

您可以通过查询cat API来检查集群中每个节点上的磁盘空间(并查看在每个节点上存储了哪些分片):

curl -s 'localhost:9200/_cat/allocation?v'
           

有关在任何特定节点磁盘空间不足时应采取的措施(删除过时的数据并将其存储在群集之外,添加更多节点,升级硬件等),请查阅本文,以获取有关选择的选项。

如果您的节点具有较大的磁盘容量,则85%的低水印可能太低。您可以使用“群集更新设置” API来更改cluster.routing.allocation.disk.watermark.low和/或cluster.routing.allocation.disk.watermark.high。例如,此堆栈溢出线程指出,如果您的节点具有5TB磁盘容量,则可以安全地将低磁盘水位标记提高到90%:

curl -XPUT 'localhost:9200/_cluster/settings' -d
'{
	"transient": {	
	      "cluster.routing.allocation.disk.watermark.low": "90%"
	}
}'
           

如果您希望配置更改在群集重新启动后仍然存在,请将“ transient”替换为“ persistent”,或在配置文件中更新这些值。您可以选择使用字节值或百分比值来更新这些设置,但请务必记住Elasticsearch文档中的这一重要说明:“百分比值是指已使用的磁盘空间,而字节值是指可用磁盘空间。”

原因6:多个es版本

仅在运行多个版本的Elasticsearch的集群中才会出现此问题(可能在滚动升级过程中)。根据Elasticsearch文档,主节点不会将主碎片的副本分配给运行旧版本的任何节点。例如,如果主分片在1.4版上运行,则主服务器将无法将该分片的副本分配给运行1.4版之前的任何版本的任何节点。

如果您尝试手动将分片从较新版本的节点重新路由到较旧版本的节点,则会看到类似以下错误:

[NO(target node version [XXX] is older than source node version [XXX])]
           

Elasticsearch不支持回滚到以前的版本,仅支持升级。如果确实是手头的问题,那么升级运行旧版本的节点应该可以解决该问题。

参考url: https://www.datadoghq.com/blog/elasticsearch-unassigned-shards/

继续阅读