ElasticSearch恢复健康状态
报错:
org.elasticsearch.action.search.SearchPhaseExecutionException: all shards failed
1. 检查健康状态
curl --user 用户名:密码 -XGET http://本机ip:端口/_cluster/health\?pretty
{
"cluster_name" : "elasticsearch",
"status" : "red",
"timed_out" : false,
"number_of_nodes" : 1,
"number_of_data_nodes" : 1,
"active_primary_shards" : 59,
"active_shards" : 59,
"relocating_shards" : 0,
"initializing_shards" : 3,
"unassigned_shards" : 33,
"delayed_unassigned_shards" : 0,
"number_of_pending_tasks" : 7,
"number_of_in_flight_fetch" : 0,
"task_max_waiting_in_queue_millis" : 615,
"active_shards_percent_as_number" : 62.10526315789474
}
green为健康状态,red为不健康,yellow在两者之间,但仍不健康。
从上面的 unassigned_shards
可以存在大量分片没有被分配,
-
如果是集群环境,可以考虑使用
POST /_cluster/reroute
强制把问题分片分配到其中一个节点上了 -
但是对于目前的单机环境,从上面截图可以看出存在5个 unassigned 的分片,新建索引时候,分片数为5,副本数为1,新建之后集群状态成为yellow,其根本原因是因为集群存在没有启用的副本分片。
解决办法就是,在单节点的elasticsearch集群,删除存在副本分片的索引,新建索引的副本都设为0。然后再查看集群状态
通过如果下命令,设置
number_of_replicas=0
,将副本调整为0. 如下图所示,es变成了“绿色”
curl --user 用户名:密码 -XPUT 'http://127.0.0.1:9200/_settings' -H 'content-Type:application/json' -d'
{
"number_of_replicas": 0
}'
再次查看健康状态:
{
"cluster_name" : "elasticsearch",
"status" : "green",
"timed_out" : false,
"number_of_nodes" : 1,
"number_of_data_nodes" : 1,
"active_primary_shards" : 95,
"active_shards" : 95,
"relocating_shards" : 0,
"initializing_shards" : 0,
"unassigned_shards" : 0,
"delayed_unassigned_shards" : 0,
"number_of_pending_tasks" : 0,
"number_of_in_flight_fetch" : 0,
"task_max_waiting_in_queue_millis" : 0,
"active_shards_percent_as_number" : 100.0
}
green!
查看每个分片的状态
http://localhost:9200/_cat/shards?h=index,shard,prirep,state,unassigned.reason
根据es官网,各种副本分片创建失败原因如下:
1)INDEX_CREATED:由于创建索引的API导致未分配。
2)CLUSTER_RECOVERED :由于完全集群恢复导致未分配。
3)INDEX_REOPENED :由于打开open或关闭close一个索引导致未分配。
4)DANGLING_INDEX_IMPORTED :由于导入dangling索引的结果导致未分配。
5)NEW_INDEX_RESTORED :由于恢复到新索引导致未分配。
6)EXISTING_INDEX_RESTORED :由于恢复到已关闭的索引导致未分配。
7)REPLICA_ADDED:由于显式添加副本分片导致未分配。
8)ALLOCATION_FAILED :由于分片分配失败导致未分配。
9)NODE_LEFT :由于承载该分片的节点离开集群导致未分配。
10)REINITIALIZED :由于当分片从开始移动到初始化时导致未分配(例如,使用影子shadow副本分片)。
11)REROUTE_CANCELLED :作为显式取消重新路由命令的结果取消分配。
12)REALLOCATED_REPLICA :确定更好的副本位置被标定使用,导致现有的副本分配被取消,出现未分配。
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])]
大体就这几种情况,你可以根据自己的观察到的现象去判断。
知识点#
副本分片 主要目的就是为了故障转移,如果持有主分片的节点挂掉了,一个副本分片就会晋升为主分片的角色。
所以副本分片和主分片是不能放到一个节点上面的,可是在只有一个节点的集群里,副本分片没有办法分配到其他的节点上,所以出现所有副本分片都unassigned得情况。因为只有一个节点,如果存在主分片节点挂掉了,那么整个集群理应就挂掉了,不存在副本分片升为主分片的情况。