彻底解决 es 的 unassigned shards 症状


es 集群里面的分片是分配在多台node上的,为的就是高可用,比如你的某台机器crash了,那么集群就会让其他副本顶上来,免得出现某个分片不能提供服务的情况。

既然这样,难免还是会出现 UNASSIGNED shards 的错误,今天我们来探究下原因和解决之道。

如果你的数据无关紧要(比如监控数据,丢了就丢了,因为你只关注当前的), 就可以直接简单粗暴的删掉出问题的分片,当然你的数据很重要的时候,就不能这样干了,下面我们来看下几种情况。

  • Shard allocation 过程中的延迟机制
  • nodes 数小于分片副本数
  • 检查是否开启 cluster.routing.allocation.enable 参数
  • 分片的历史数据丢失了
  • 磁盘不够用了
  • es 的版本问题

一、发现 unassigned 的分片

es 有api可以查看所有的 unassigned 的分片

curl -XGET localhost:9200/_cat/shards?h=index,shard,prirep,state,unassigned.reason| grep UNASSIGNED

这样你就可以清楚的看到 index, 分片数, 主分片还是副本分片,是否处于 unassigned 的状态, 甚至还有unassigned 的原因,比如

constant-updates        0 p UNASSIGNED NODE_LEFT node_left[NODE_NAME]

如果这个index 已经不用了, 直接删除 index, 这样这些 unassigned 的分片也会被干掉, 集群恢复正常

curl -XDELETE 'localhost:9200/index_name/'

二、Shard allocation 过程中的延迟机制

当一个 点从集群中下线了, es 有一个延迟拷贝机制, 默认是等一分钟之后再开始处理 unassigned 的分片, 该做 rebalance的去 rebalance,只所以这样, 是因为es担心如果一个点只是中断了片刻, 或者临时下线某台机器,就立马大动干戈,就尴尬了,比如下面这种情形

  • Node(节点) 19 在网络中失联了(某个家伙踢到了电源线)
  • Master 立即注意到了这个节点的离线,它决定在集群内提拔其他拥有 Node 19 上面的主分片对应的副本分片为主分片
  • 在副本被提拔为主分片以后,master 节点开始执行恢复操作来重建缺失的副本。集群中的节点之间互相拷贝分片数据,网卡压力剧增,集群状态尝试变绿。
  • 由于目前集群处于非平衡状态,这个过程还有可能会触发小规模的分片移动。其他不相关的分片将在节点间迁移来达到一个最佳的平衡状态

与此同时,那个踢到电源线的倒霉管理员,把服务器插好电源线进行了重启,现在节点 Node 19 又重新加入到了集群。不幸的是,这个节点被告知当前的数据已经没有用了, 数据已经在其他节点上重新分配了。所以 Node 19 把本地的数据进行删除,然后重新开始恢复集群的其他分片(然后这又导致了一个新的再平衡)

如果这一切听起来是不必要的且开销极大,那就对了。是的,不过前提是你知道这个节点会很快回来。如果节点 Node 19 真的丢了,上面的流程确实正是我们想要发生的。

这个默认的延迟分配分片的实际是1分钟, 当然你可以设置这个时间

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

三、nodes 数小于分片副本数

当一个nodes 被下掉之后, master 节点会重新 reassigns 这台nodes上的所有分片, 尽可能的把同一个分片的不同副本分片和主分片分配到不同的node上,但是如果你设置的一个分片的 副本数目太多, 导致根本没法一个 node上分配一个,就会出现问题, 会导致 es 没法进行 reassign, 这样就会出现 unassigned 的分片。

从一开始创建index 的时候就要保证N >= R + 1这里 N 代表 node的个数, R代表你index 的副本数目。

怎么解决呢, 要么增加 nodes 个数,要么减少副本数

curl -XPUT 'localhost:9200/<INDEX_NAME>/_settings' -d '{"number_of_replicas": 2}'

我们上个例子中,就把 副本数目减少到 2个, 问题解决。

四、检查是否开启 cluster.routing.allocation.enable 参数

Shard allocation 功能默认都是开启的, 但是如果你在某个时刻关闭了,这个功能(比如滚动重启的情形, https://www.elastic.co/guide/en/elasticsearch/guide/current/_rolling_restarts.html ), 后面忘了开启了,也会导致问题, 你可以使用下面这个命令开开启下

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

恢复之后, 你可以从监控上,看到 unassigned shards 逐渐恢复

看监控中,几个index都恢复了,好像还有constant-updates这个index 没有好,我们看下是否还有其他原因

五、分片的历史数据丢失了

我们现在的问题是这样, constant-updates 这个index 的第 0个分片处于 unassigned 状态, 创建这个index 的时候 每个分片只有 一个 主分片,没有其他副本, 数据没有副本, 集群检测到这个分片的 全局状态文件,但是没有找到原始数据, 就没法进行恢复。

还有一种可能是这样, 当一个node 重启的时候, 会重新连接集群, 然后把自己的 disk 文件信息汇报上去, 这时候进行恢复,如果这个过程出现了问题,比如存储坏掉了,那么当前分片还是没法恢复正常。

这个时候,你可以考虑下,是继续等待原来的那台机器恢复然后加入集群,还是重新强制分配 这些 unassigned 的分片, 重新分配的时候也可以使用备份数据。

如果你打算重新强制分配主分片,可以使用下面的命令 , 记得带上"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}

因为没有当前分配的分片是没有主分片了。

当然你在重新强制分配主分片的时候,可以创建一个 empty 的主分片,也就是老数据我不要了, 这个时候,如果失联的 node 重新加入集群后, 就把自己降级了, 分片的数据也会使用 这个 empty 的主分片覆盖, 因为它已经变成过时的版本了。

POST _cluster/reroute  
{
  "commands" : [ {
        "allocate_empty_primary" :
            {
              "index" : "constant-updates", "shard" : 0, "node" : "<NODE_NAME>", "accept_data_loss" : true
            }
        }
  ]
}

这个命令就可以创建一个 empty 的主分片。

六、磁盘不够用了

如果很多nodes的磁盘都触及low disk watermark, 没有足够的磁盘空间用来分配分片, 这时候同样会出现 unassigned 的分片。 一般这个 磁盘使用超过 85 % , 就会触及low disk watermark。

你可以使用下面的api来查看当前磁盘使用情况

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

你可以参考 这篇文章来 应对磁盘不够用的情况, https://www.datadoghq.com/blog/elasticsearch-performance-scaling-problems/#toc-problem-2-help-data-nodes-are-running-out-of-disk-space1。

这个触及low disk watermark的磁盘使用比例也是可以设置的,

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

七、es 的版本问题

哦,差点忘了还有一种极端情况, 就是你升级了某个node的版本, master node 会不认这个跟它版本不同的的node, 也不会在上面分配分片。

如果你手动强制往上面分配分片,会报错。

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

大体就这几种情况,你可以根据自己的观察到的现象去判断。

原文链接

posted @ 2020-12-27 13:17  吕振江  阅读(10197)  评论(0编辑  收藏  举报
浏览器标题切换
浏览器标题切换end