ElasticSearch:未分配的碎片,如何解决?


165

我有一个具有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
    }
}'

Answers:


117

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

# 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线程池可能太小

最后,您可以使用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
        }
    }]
}'

3
当我这样做时,我得到了:{ "error" : "ElasticsearchIllegalArgumentException[[allocate] failed to find [logstash-2015.01.05][1] on the list of unassigned shards]", "status" : 400 } 即使我看到碎片是ES-Head中未分配的碎片之一
wjimenez5271 2015年

顺便说一句,其他分片确实做了工作,这些分片被列出为未分配,然后其余的分片自行修复。
wjimenez5271

这是很好的建议。
Yehosef

1
从5.0版开始,“分配”命令已更改为提供更多选项 -上面的示例现在为“ allocate_empty_primary”,省略了“ allow_primary”参数。
JMB

4
-H 'Content-Type: application/json'如果出现错误,则需要添加Content-Type header [application/x-www-form-urlencoded] is not supported
luckydonald

56

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

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

<index>您认为是罪魁祸首的索引在哪里?如果您不知道,只需在所有节点上运行此命令:

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

我还将这一行添加到我的yaml配置中,此后,服务器/服务的任何重新启动都没有问题。碎片立即重新分配。

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

参考资料


2
为了解决版本1.1.1中的问题,我应该使用cluster.routing.allocation.enable = none吗?
user3175226

1
分配禁止不再记录在那里,至少不会像十一月20的

3
请注意,路由分配是群集范围的设置,因此将命令发送到哪个节点都没有关系。
Wilfred Hughes

我在es yml文件中都添加了它们。index.routing.allocation.disable_allocation : false cluster.routing.allocation.enable: none但是仍然显示未分配的碎片。.原因可能是什么?
bagui 2015年

1
在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" } ],
Janac Meena

39

这个小小的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

像魅力一样工作。谢谢!
Paulo Pires 2015年

我收到此错误:<br> {“错误”:“ JsonParseException [意外的字符r(','(代码44)):预期的有效值(数字,字符串,数组,对象,'true','false'或'空')\ n在[来源:[B @ 3b1fadfb;行:6,柱:27]”, “状态”:500}结果,我应该怎么做修复它
biolinh

万分感谢!它节省了宝贵的时间!
Sathish

脚本引发错误:{"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}
Janac Meena

17

唯一适合我的方法是更改​​number_of_replicas(我有2个副本,因此我将其更改为1,然后又更改为2)。

第一:

PUT /myindex/_settings
{
    "index" : {
        "number_of_replicas" : 1
     }
}

然后:

PUT /myindex/_settings
{
    "index" : {
        "number_of_replicas" : 2
     }
}

(我已经在这个问题中接受了它)


9

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

如果即使在应用以下配置后es仍无法自动分配分片,那么您必须自己强制分配分片。ES的官方链接

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

下面的数组包含要在其中平衡未分配碎片的节点列表

#!/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

该脚本不起作用,也就是说,在我运行它之后,我仍然拥有未分配的碎片。
克里斯F,

@ChrisF在第1行中:您需要用实际的节点名称替换node1,node2,node3。您可以使用curl localhost:9200 / _cat / nodes获得它们。
sidi

6

我今天也遇到了相同的分片分配问题。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/…–
Fawix

2
为了使上面的脚本能与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}应用Fawix的建议后得到平衡
Janac Meena

6

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

看这篇文章: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"
  }
}

因此,如果使用的硬盘空间小于90%,它将进行分配;如果使用的硬盘空间大于95%,它将将分片移动到群集中的另一台计算机;并且每1分钟检查一次。


4

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

希望它能对某人有所帮助!:)


4

在我的情况下,当我创建一个新索引时,默认的number_of_replicas设置为1。群集中的节点数只有一个,因此没有多余的节点来创建副本,因此运行状况变为黄色。因此,当我使用settings属性创建索引并将number_of_replicas设置 为0时,它工作正常。希望这可以帮助。

PUT /customer
{
    "settings": {
        "number_of_replicas": 0
    }
}

3

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

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

[否(目标节点版本[1.4.2]早于源节点版本[1.4.4]))]

在将旧节点更新为1.4.4之后,这些节点开始与其他良好节点进行resnc。


3

我也遇到了这个问题,并且找到了解决此问题的简便方法。

  • 获取未分配碎片的索引

    $ curl -XGET http://172.16.4.140:9200/_cat/shards
    
  • 安装策展人工具,并使用它删除索引

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

    注意:在我的情况下,索引是当天的logstash 2016-04-21

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

1
@sim,非常感谢您对我的回答所做的编辑。我的编辑能力很差,将更加关注它。
user3391471

对我来说,是:curator_cli --host 127.0.0.1 delete_indices --filter_list '[{"filtertype":"pattern","kind":"prefix","value":"logstash-"}]'
盖伊

2

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

首先,我将描述我的情况。我在ElasticSearch集群中有两个节点,它们可以彼此找到,但是当我创建设置为“ number_of_replicas”的索引时:2,“ number_of_shards”:5,ES显示黄色信号,而unassigned_shards为5。

发生问题是因为number_of_replicas的值设置为1时,一切都很好。


4
副本数应始终为您拥有的节点数的N-1。因此,在与2个节点的情况下,节点1包含主碎片,而他其他节点具有该副本,因此你的副本的数目应被设置为1。N = 2,N - 1 = 1
SLM

1

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


1

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

解决方案是编辑配置,将“ 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

1

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

.....

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

“获取/ _cat / shards?h = [INDEXNAME],分片,优先级,状态,未分配原因。”

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


从5.6.3版开始,命令应该为/_cat/shards/[INDEXNAME]?h=,shard,prirep,state,unssigned.reason
fasantos

0

可能会有帮助,但是尝试以嵌入式模式运行ES时遇到了这个问题。解决方法是确保Node设置了local(true)。



0

我遇到了完全相同的问题。可以通过在重新启动Elasticsearch之前将分片分配临时设置为false来防止此问题,但这不会解决未分配的分片已经存在的问题。

就我而言,这是由于数据节点上的可用磁盘空间不足所致。重新分配后,未分配的碎片仍位于数据节点上,但主节点无法识别这些碎片。

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


0

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


0

我有两个带有未分配碎片的索引,这些碎片似乎并没有自我修复。我最终通过临时添加一个额外的数据节点[1]解决了这一问题。在索引变得健康并且一切都稳定为绿色之后,我删除了多余的节点,系统得以重新平衡(再次)并处于健康状态。

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


...一段时间过去了...

好吧,这次只是添加一个节点似乎不起作用(在等待几分钟后,某件事才发生),因此我开始研究REST API。

GET /_cluster/allocation/explain

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

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

然后,我进行了以下简单的POST [2] ,没有主体这使事情陷入了混乱 ……

POST /_cluster/reroute

其他说明:


[1]如果您有足够的净空,在Kubernetes中非常容易做:只需通过仪表板扩展有状态集即可。

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


0

我只是先增加了

“ index.number_of_replicas”

减少1(直到节点同步),然后再减少1,这将有效地删除未分配的分片,并且群集再次变为绿色,而不会丢失任何数据。

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

希望这可以帮助。


0

处理损坏的分片时,可以将复制因子设置为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。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.