ElasticSearch:未分配的碎片,如何修复?

Posted

技术标签:

【中文标题】ElasticSearch:未分配的碎片,如何修复?【英文标题】:ElasticSearch: Unassigned Shards, how to fix? 【发布时间】:2013-11-26 20:41:55 【问题描述】:

我有一个 4 个节点的 ES 集群:

number_of_replicas: 1
search01 - master: false, data: false
search02 - master: true, data: true
search03 - master: false, data: true
search04 - master: false, data: true

我不得不重新启动 search03,当它回来时,它重新加入集群没有问题,但留下了 7 个未分配的分片。


  "cluster_name" : "tweedle",
  "status" : "yellow",
  "timed_out" : false,
  "number_of_nodes" : 4,
  "number_of_data_nodes" : 3,
  "active_primary_shards" : 15,
  "active_shards" : 23,
  "relocating_shards" : 0,
  "initializing_shards" : 0,
  "unassigned_shards" : 7

现在我的集群处于黄色状态。解决此问题的最佳方法是什么?

删除(取消)分片? 将分片移动到另一个节点? 将分片分配给节点? 将“number_of_replicas”更新为 2? 完全不同的东西?

有趣的是,当添加一个新索引时,该节点开始处理它并与集群的其余部分配合得很好,它只是留下了未分配的分片。

请继续提问:我是否做错了什么导致这种情况发生?我对重新启动节点时以这种方式运行的集群没有多大信心。

注意:如果您出于某种原因正在运行单节点集群,您可能只需要执行以下操作:

curl -XPUT 'localhost:9200/_settings' -d '

    "index" : 
        "number_of_replicas" : 0
    
'

【问题讨论】:

【参考方案1】:

ES 7.4.2 上的类似问题,命令已更改。正如答案中已经提到的,首先要检查GET _cluster/allocation/explain?pretty,然后检查POST _cluster/reroute?retry_failed

主要 您必须通过 "accept_data_loss": true 获得主分片

POST _cluster/reroute

    "commands": [
        "allocate_stale_primary": 
            "index": "filebeat-7.4.2-xxxx",
            "shard": 0,
            "node": "my_node",
            "accept_data_loss": false
        
    ]

副本

POST _cluster/reroute

    "commands": [
        "allocate_replica": 
            "index": "filebeat-7.4.2-xxxx",
            "shard": 0,
            "node": "my_other_node"
        
    ]

cluster-reroute doc

【讨论】:

【参考方案2】:

如果您有未分配的分片,通常第一步是调用allocation explain API 并查找原因。根据原因,你会做一些事情。以下是我想到的一些:

节点没有足够的磁盘空间(检查disk-based allocation设置) 由于allocation is disabled 或allocation filtering 或awareness 等限制,节点无法分配分片(例如,节点位于集群的错误一侧,例如其他可用区或热节点或热节点) 加载分片时出错。例如。文件校验和失败,分析器引用的同义词文件丢失

有时它有助于快速启动它,例如使用 Cluster Reroute API 手动分配分片,或者禁用和重新启用副本。

如果您需要有关操作 Elasticsearch 的更多信息,请查看 Sematext 的 Elasticsearch Operations training(免责声明:我正在提供)。

【讨论】:

【参考方案3】:

首先使用cluster health API 获取集群的当前运行状况,其中红色表示缺少一个或多个主分片,黄色表示缺少一个或多个副本分片。

在此之后,使用cluster allocation explain API 了解为什么缺少特定分片并且 elasticsearch 无法在数据节点上分配它。

一旦找到确切的根本原因,请尝试解决问题,这通常需要更改一些集群设置(在@wilfred 回答earlier 中提到)但在某些情况下,如果它的副本分片,并且您有另一个副本如果有相同的分片(即另一个副本)可用,您可以使用update replica setting 减少副本数,然后在需要时再次增加它。

除此之外,如果您的集群分配 API 提到它没有有效的数据节点来分配分片,那么您需要添加新的数据节点,或者更改 shard allocation awareness settings。

【讨论】:

【参考方案4】:

我也遇到了类似的错误。这发生在我身上,因为我的一个数据节点已满,并且由于分片分配失败。如果存在未分配的分片,并且您的集群是 RED,并且很少有索引也是 RED,那么在这种情况下,我已按照以下步骤操作,这些步骤就像冠军一样工作。 在 kibana 开发工具中-

GET _cluster/allocation/explain

如果有任何未分配的分片,那么您将获得详细信息,否则将抛出错误。

只需在命令下方运行即可解决所有问题-

POST _cluster/reroute?retry_failed

感谢 -https://github.com/elastic/elasticsearch/issues/23199#issuecomment-280272888

【讨论】:

非常感谢,帮我节省了很多时间。【参考方案5】:

这也可能是磁盘空间的原因, 在 Elasticsearch 7.5.2 中,默认情况下,如果磁盘使用率高于 85%,则不会将副本分片分配给任何其他节点。

这可以通过设置不同的阈值或在 .yml 中或通过 Kibana 禁用它来解决

PUT _cluster/settings

  "persistent": 
    "cluster.routing.allocation.disk.threshold_enabled": "false"
  

【讨论】:

【参考方案6】:

在处理损坏的分片时,您可以将复制因子设置为 0,然后将其设置回原始值。这应该会清除大部分(如果不是全部)损坏的分片,并重新定位集群中的新副本。

将未分配副本的索引设置为使用复制因子 0:

curl -XGET http://localhost:9200/_cat/shards |\
  grep UNASSIGNED | grep ' r ' |\
  awk 'print $1' |\
  xargs -I  curl -XPUT http://localhost:9200//_settings -H "Content-Type: application/json" \
  -d ' "index": "number_of_replicas": 0'

将它们设置回 1:

curl -XGET http://localhost:9200/_cat/shards |\
  awk 'print $1' |\
  xargs -I  curl -XPUT http://localhost:9200//_settings -H "Content-Type: application/json" \
  -d ' "index": "number_of_replicas": 1'

注意:如果您对不同的索引有不同的复制因子,请不要运行此命令。这会将所有索引的复制因子硬编码为 1。

【讨论】:

【参考方案7】:

我只是先增加了

“index.number_of_replicas”

减 1(等到节点同步),然后再减 1,这有效地删除了未分配的分片,集群再次变为绿色,没有丢失任何数据的风险。

我相信有更好的方法,但这对我来说更容易。

希望这会有所帮助。

【讨论】:

【参考方案8】:

我有两个索引,其中未分配的分片似乎无法自我修复。我最终通过临时添加一个额外的数据节点[1]解决了这个问题。在指数变得健康并且一切稳定为绿色后,我删除了额外的节点,系统能够(再次)重新平衡并进入健康状态。

最好避免一次杀死多个数据节点(这就是我进入这种状态的方式)。很可能,我没有为至少一个分片保留任何副本/副本。幸运的是,Kubernetes 保留了磁盘存储,并在我重新启动数据节点时重新使用它。


...已经过了一段时间...

好吧,这次只是添加一个节点似乎没有用(在等待了几分钟之后),所以我开始在 REST API 中四处寻找。

GET /_cluster/allocation/explain

这显示了我的新节点"decision": "YES"

顺便说一句,由于"the node is above the low watermark cluster setting",所有预先存在的节点都有"decision": "NO"。所以这可能与我之前提到的情况不同。

然后我做了以下简单的 POST[2]没有正文让事情进展顺利...

POST /_cluster/reroute

其他说明:

非常有帮助:https://datadoghq.com/blog/elasticsearch-unassigned-shards

其他可能有效的方法。将cluster_concurrent_rebalance 设置为0,然后设置为null——正如我演示的here。


[1]如果你有足够的空间,在 Kubernetes 中很容易做到:只需通过仪表板扩展有状态集。

[2] 使用 Kibana 的“开发工具”界面,我不必费心使用 SSH/exec shell。

【讨论】:

【参考方案9】:

好的,我在 ES 支持的帮助下解决了这个问题。向所有节点(或您认为是问题原因的节点)上的 API 发出以下命令:

curl -XPUT 'localhost:9200/<index>/_settings' \
    -d '"index.routing.allocation.disable_allocation": false'

其中&lt;index&gt; 是您认为是罪魁祸首的索引。如果您不知道,只需在所有节点上运行:

curl -XPUT 'localhost:9200/_settings' \
    -d '"index.routing.allocation.disable_allocation": false'

我还将这一行添加到我的 yaml 配置中,从那时起,服务器/服务的任何重新启动都没有问题。分片立即重新分配回来。

FWIW,要回答一个经常受到追捧的问题,请将 MAX_HEAP_SIZE 设置为 30G,除非您的计算机的 RAM 小于 60G,在这种情况下,请将其设置为可用内存的一半。

参考文献

Shard Allocation Awareness

【讨论】:

要在 1.1.1 版本中解决这个问题,我应该使用 cluster.routing.allocation.enable = none 吗? 那里不再记录分配禁用,至少截至 11 月 20 日没有。 请注意,路由分配是集群范围的设置,因此您将命令发送到哪个节点并不重要。 我在我的 es yml 文件中添加了两者。 index.routing.allocation.disable_allocation : false cluster.routing.allocation.enable: none 但是仍然显示未分配的分片.. 可能是什么原因? 在 6.8 版中出现错误: "type": "illegal_argument_exception", "reason": "unknown setting [index.routing.allocation.disable_allocation] please check that any required plugins are installed, or check the breaking changes documentation for removed settings" ],【参考方案10】:

对我来说,这是通过从开发控制台运行以下命令解决的:“POST /_cluster/reroute?retry_failed”

.....

我首先查看索引列表,看看哪些索引是红色的,然后运行

"get /_cat/shards?h=[INDEXNAME],shard,prirep,state,unassigned.reason"

并看到它的分片卡在 ALLOCATION_FAILED 状态,因此运行上面的重试导致它们重新尝试分配。

【讨论】:

从 5.6.3 版开始,命令应该是 get /_cat/shards/[INDEXNAME]?h=,shard,prirep,state,unassigned.reason【参考方案11】:

如果以下配置设置为 all,Elasticsearch 会自动分配分片。可以使用rest api as well 设置此配置 cluster.routing.allocation.enable: 全部

如果即使在应用以下配置后,es 无法自动分配分片,那么您必须自己强制分配分片。 ES official link for this

我编写了一个脚本来强制跨集群分配所有未分配的分片。

下面的数组包含您想要平衡未分配分片的节点列表

#!/bin/bash
array=( node1 node2 node3 )
node_counter=0
length=$#array[@]
IFS=$'\n'
for line in $(curl -s 'http://127.0.0.1:9200/_cat/shards'|  fgrep UNASSIGNED); do
    INDEX=$(echo $line | (awk 'print $1'))
    SHARD=$(echo $line | (awk 'print $2'))
    NODE=$array[$node_counter]
    echo $NODE
    curl -XPOST 'http://127.0.0.1:9200/_cluster/reroute' -d '
        "commands": [
        
            "allocate": 
                "index": "'$INDEX'",
                "shard": '$SHARD',
                "node": "'$NODE'",
                "allow_primary": true
            
        
        ]
    '
    node_counter=$(((node_counter)%length +1))
done

【讨论】:

这个脚本不起作用,也就是说,我运行它之后,我仍然有未分配的碎片。 @ChrisF 在 line1 中:您需要将 node1、node2、node3 替换为实际的节点名称。您可以使用 curl localhost:9200/_cat/nodes 获取它们。【参考方案12】:

我尝试删除未分配的分片或手动将它们分配给特定的数据节点。它不起作用,因为未分配的碎片不断出现,并且健康状态一遍又一遍地“红色”。 然后我注意到其中一个数据节点卡在“重新启动”状态。我减少了数据节点的数量,杀死了它。问题不再重现。

【讨论】:

【参考方案13】:

就我而言,已达到硬盘空间上限。

看这篇文章:https://www.elastic.co/guide/en/elasticsearch/reference/current/disk-allocator.html

基本上,我跑了:

PUT /_cluster/settings

  "transient": 
    "cluster.routing.allocation.disk.watermark.low": "90%",
    "cluster.routing.allocation.disk.watermark.high": "95%",
    "cluster.info.update.interval": "1m"
  

如果使用 95%的硬盘空间,则将分片移动到集群中的另一台机器;它每 1 分钟检查一次。

【讨论】:

【参考方案14】:

我也遇到这种情况,终于解决了。

首先,我将描述我的情况。我在 ElasticSearch 集群中有两个节点,它们可以相互找到,但是当我使用设置 "number_of_replicas" : 2、"number_of_shards" : 5 创建索引时,ES 显示黄色信号并且 unassigned_shards 为 5。

出现问题是因为number_of_replicas的值,当我将其值设置为1时,一切正常。

【讨论】:

副本数应始终为您拥有的节点数的 N-1。因此,在您有 2 个节点的场景中,其中 1 个节点包含主分片,而另一个节点具有副本,因此您的副本数应设置为 1。N = 2,N - 1 = 1。【参考方案15】:

在我的例子中,当我创建一个新的 index 时,默认的 number_of_replicas 设置为 1。而且我的集群中的节点数只有一个,所以没有额外的节点来创建副本,所以运行状况变成了黄色。 因此,当我使用 settings 属性创建索引并将 number_of_replicas 设置为 0 时,它工作正常。希望这会有所帮助。

PUT /customer

    "settings": 
        "number_of_replicas": 0
    

【讨论】:

【参考方案16】:

我也遇到了这个问题,我找到了一个简单的方法来解决它。

获取未分配分片的索引

$ curl -XGET http://172.16.4.140:9200/_cat/shards

安装curator Tools,并用它来删除索引

$ curator --host 172.16.4.140 delete indices --older-than 1 \
       --timestring '%Y.%m.%d' --time-unit days --prefix logstash

注意:就我而言,索引是 2016 年 4 月 21 日当天的 logstash

然后再次检查分片,所有未分配的分片都消失了!

【讨论】:

@sim,非常感谢您对我的回答进行编辑。我编辑很差,以后会多注意的。 对我来说是:curator_cli --host 127.0.0.1 delete_indices --filter_list '["filtertype":"pattern","kind":"prefix","value":"logstash-"]'【参考方案17】:

我尝试了上面的几个建议,但不幸的是,它们都没有奏效。在应用程序写入错误的较低环境中,我们有一个“日志”索引。它是一个单节点集群。为我解决的问题是检查节点的 YML 配置文件,并看到它仍然具有默认设置“gateway.expected_nodes:2”。这覆盖了我们拥有的任何其他设置。每当我们在这个节点上创建一个索引时,它会尝试将 5 个分片中的 3 个分散到虚拟的第二个节点。因此,这些将显示为未分配,并且永远无法移动到第一个也是唯一的节点。

解决方案是编辑配置,将设置“gateway.expected_nodes”更改为 1,这样它就不会在集群中寻找它永远找不到的兄弟,并重新启动 Elastic 服务实例。此外,我不得不删除索引,并创建一个新的。创建索引后,分片都出现在第一个也是唯一的节点上,没有一个是未分配的。

# Set how many nodes are expected in this cluster. Once these N nodes
# are up (and recover_after_nodes is met), begin recovery process immediately
# (without waiting for recover_after_time to expire):
#
# gateway.expected_nodes: 2
gateway.expected_nodes: 1

【讨论】:

【参考方案18】:

我今天遇到了同样的分片分配问题。那个脚本 W. Andrew Loe III 在他的回答中提出对我不起作用,所以我对其进行了一些修改,终于奏效了:

#!/usr/bin/env bash

# The script performs force relocation of all unassigned shards, 
# of all indices to a specified node (NODE variable)

ES_HOST="<elasticsearch host>"
NODE="<node name>"

curl $ES_HOST:9200/_cat/shards > shards
grep "UNASSIGNED" shards > unassigned_shards

while read LINE; do
  IFS=" " read -r -a ARRAY <<< "$LINE"
  INDEX=$ARRAY[0]
  SHARD=$ARRAY[1]

  echo "Relocating:"
  echo "Index: $INDEX"
  echo "Shard: $SHARD"
  echo "To node: $NODE"

  curl -s -XPOST "$ES_HOST:9200/_cluster/reroute" -d "
    \"commands\": [
       
         \"allocate\": 
           \"index\": \"$INDEX\",
           \"shard\": $SHARD,
           \"node\": \"$NODE\",
           \"allow_primary\": true
         
       
     ]
  "; echo
  echo "------------------------------"
done <unassigned_shards

rm shards
rm unassigned_shards

exit 0

现在,我不是 Bash 专家,但脚本确实适合我的情况。请注意,您需要为“ES_HOST”和“NODE”变量指定适当的值。

【讨论】:

不幸的是 ES5x 破坏了兼容性:elastic.co/guide/en/elasticsearch/reference/5.1/… 为了使上面的脚本能够与 ES5x 一起使用,请将 allocate 替换为 allocate_empty_primary 并将 \"allow_primary\": true 替换为 \"accept_data_loss\": true 即使在应用了 Fawix 的建议后也得到"error":"Content-Type header [application/x-www-form-urlencoded] is not supported","status":406【参考方案19】:

默认情况下,Elasticsearch 会动态地将分片重新分配给节点。但是,如果您禁用了分片分配(也许您执行了 rolling restart 并忘记重新启用它),您可以重新启用分片分配。

# v0.90.x and earlier
curl -XPUT 'localhost:9200/_settings' -d '
    "index.routing.allocation.disable_allocation": false
'

# v1.0+
curl -XPUT 'localhost:9200/_cluster/settings' -d '
    "transient" : 
        "cluster.routing.allocation.enable" : "all"
    
'

然后,Elasticsearch 将照常重新分配分片。这可能会很慢,请考虑提高indices.recovery.max_bytes_per_seccluster.routing.allocation.node_concurrent_recoveries 以加快速度。

如果您仍然看到问题,则可能是其他问题,因此请查看您的 Elasticsearch 日志中的错误。如果你看到EsRejectedExecutionException 你的线程池may be too small。

最后,您可以使用reroute API 将分片显式重新分配给节点。

# Suppose shard 4 of index "my-index" is unassigned, so you want to
# assign it to node search03:
curl -XPOST 'localhost:9200/_cluster/reroute' -d '
    "commands": [
        "allocate": 
            "index": "my-index",
            "shard": 4,
            "node": "search03",
            "allow_primary": 1
        
    ]
'

【讨论】:

当我这样做时,我得到了: "error" : "ElasticsearchIllegalArgumentException[[allocate] failed to find [logstash-2015.01.05][1] on the list of unassigned shards]", "status" : 400 尽管我可以看到分片是 ES-Head 中未分配的分片之一 顺便说一下,其他分片确实可以工作,但被列为未分配,然后其余分片自行修复。 这是个好建议。 自 5.0 版以来,“分配”命令 has changed to provide more options - 上面的示例现在是“allocate_empty_primary”,省略了“allow_primary”参数。 如果遇到错误Content-Type header [application/x-www-form-urlencoded] is not supported,需要添加-H 'Content-Type: application/json'【参考方案20】:

我遇到了完全相同的问题。这可以通过在重新启动 elasticsearch 之前将分片分配临时设置为 false 来防止,但是如果它们已经存在,这不会修复未分配的分片。

在我的情况下,这是由于数据节点上的可用磁盘空间不足造成的。重新启动后未分配的分片仍在数据节点上,但主节点无法识别它们。

只需从磁盘中清理 1 个节点,我就开始了复制过程。这是一个相当缓慢的过程,因为所有数据都必须从一个数据节点复制到另一个数据节点。

【讨论】:

【参考方案21】:

未分配分片的另一个可能原因是您的集群运行了多个版本的 Elasticsearch 二进制文件。

从较新版本到前一个版本的分片复制 版本将不起作用

这可能是未分配分片的根本原因。

Elastic Documentation - Rolling Upgrade Process

【讨论】:

【参考方案22】:

在我的例子中,一个具有旧共享的旧节点正在加入集群,因此我们必须关闭旧节点并删除具有未分配分片的索引。

【讨论】:

【参考方案23】:

可能会有所帮助,但我在尝试以嵌入式模式运行 ES 时遇到了这个问题。修复是确保节点设置了 local(true)。

【讨论】:

【参考方案24】:

唯一对我有用的是更改 number_of_replicas(我有 2 个副本,所以我将其更改为 1,然后再更改回 2)。

第一:

PUT /myindex/_settings

    "index" : 
        "number_of_replicas" : 1
     

然后:

PUT /myindex/_settings

    "index" : 
        "number_of_replicas" : 2
     

(我已经在this question回复了)

【讨论】:

这似乎会给网络和数据密集型集群的处理带来沉重的负担。你在大数据系统上试过吗?你能分享一下粗略的数字吗?【参考方案25】:

也许它对某人有帮助,但我遇到了同样的问题,这是由于日志太大而导致存储空间不足。

希望它可以帮助某人! :)

【讨论】:

【参考方案26】:

我遇到了同样的问题,但根本原因是版本号不同(两个节点上的 1.4.2(有问题)和两个节点上的 1.4.4(正常))。第一个和第二个答案(将“index.routing.allocation.disable_allocation”设置为 false 并将“cluster.routing.allocation.enable”设置为“all”)不起作用。

但是,@Wilfred Hughes 的回答(使用瞬态将“cluster.routing.allocation.enable”设置为“all”)给了我以下语句的错误:

[NO(目标节点版本 [1.4.2] 比源节点版本旧 [1.4.4])]

将旧节点更新到 1.4.4 后,这些节点开始与其他好的节点重新连接。

【讨论】:

【参考方案27】:

这个小 bash 脚本会强制重新分配,您可能会丢失数据。

NODE="YOUR NODE NAME"
IFS=$'\n'
for line in $(curl -s 'localhost:9200/_cat/shards' | fgrep UNASSIGNED); do
  INDEX=$(echo $line | (awk 'print $1'))
  SHARD=$(echo $line | (awk 'print $2'))

  curl -XPOST 'localhost:9200/_cluster/reroute' -d '
     "commands": [
        
            "allocate": 
                "index": "'$INDEX'",
                "shard": '$SHARD',
                "node": "'$NODE'",
                "allow_primary": true
          
        
    ]
  '
done

【讨论】:

工作就像一个魅力。谢谢! 我收到了这个错误: "error":"JsonParseException[Unexpected character (',' (code 44)): 期望一个有效值(数字、字符串、数组、对象、 'true' , 'false' 或 'null')\n 在 [Source: [B@3b1fadfb; line: 6, column: 27]]","status": 500 我应该怎么做才能修复它 非常感谢!它节省了宝贵的时间! 脚本抛出错误:"error":"Content-Type header [application/x-www-form-urlencoded] is not supported","status":406"error":"Content-Type header [application/x-www-form-urlencoded] is not supported","status":406 谢谢!为我工作(ElasticSearch 1.4.x)。

以上是关于ElasticSearch:未分配的碎片,如何修复?的主要内容,如果未能解决你的问题,请参考以下文章

Lucene和Elasticsearch中的碎片管理

elasticsearch中api详解

连续内存分配:内存碎片与分区的动态分配

清华大学操作系统(陈渝,向勇)课程笔记——连续内存分配

Elasticsearch未分配分片异常处理

Elasticsearch 未授权访问漏洞修复