64

彻底解决 es 的 unassigned shards 症状

 6 years ago
source link: http://mp.weixin.qq.com/s/qEyy2oFheI-gcqkr4s0p5g
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

彻底解决 es 的 unassigned shards 症状

Original 孙彪彪 一生数据人 2017-11-13 11:55 Posted on

首发个人公众号  spark技术分享 ,  同步个人网站  coolplayer.net ,未经本人同意,禁止一切转载

最近玩 es 玩的有点嗨, 就有了下面这篇文章, 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 的副本数目。

下面图示中,就是这样, 每个主分片有 4 个副本, 而总共只有 3个 nodes, 悲剧了。

Image

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

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

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

Image

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

下图可以看到, 当一个点下掉后再上线,但是上面竟然没有分配任何分片,

Image

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 逐渐恢复

Image
Image

看监控中,几个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])]

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

欢迎关注 spark技术分享 

                                

Image

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK