【问题标题】:ElasticSearch: Unassigned Shards, how to fix?ElasticSearch:未分配的碎片,如何修复?
【发布时间】: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
    }
}'

【问题讨论】:

    标签: elasticsearch sharding master


    【解决方案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 disabledallocation filteringawareness 等限制,节点无法分配分片(例如,节点位于集群的错误一侧,例如其他可用区或热节点或热节点)
      • 加载分片时出错。例如。文件校验和失败,分析器引用的同义词文件丢失

      有时它有助于快速启动它,例如使用 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
                

                其他说明:


                [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,在这种情况下,请将其设置为可用内存的一半。

                  参考文献

                  【讨论】:

                  • 要在 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)。
                                      猜你喜欢
                                      • 2018-01-09
                                      • 1970-01-01
                                      • 2014-07-02
                                      • 1970-01-01
                                      • 1970-01-01
                                      • 1970-01-01
                                      • 2014-10-02
                                      • 1970-01-01
                                      • 2016-07-28
                                      相关资源
                                      最近更新 更多