Elasticsearch的使用过程中,经常会遇到各种各样的问题。今天就来和大家分享一个我实际遇到的问题及解决过程:某组件往Elasticsearch写入数据时速度突然变慢,数据大量积压。查看集群状态后发现,Elasticsearch集群呈红色,这意味着集群出现了严重问题。经过排查,发现是索引关闭重开导致的。下面我就详细讲讲整个排查和解决问题的经过,希望能给大家一些参考。

集群异常现象及初步推测

当时,有个组件负责向Elasticsearch写入数据,突然就出现了写入速度大幅下降的情况,数据一直积压着,无法及时写入。第一反应就是Elasticsearch集群可能压力过大,毕竟数据写入异常大概率和集群状态有关。于是赶紧去查看Elasticsearch集群的状态,果不其然,集群处于red(红色)状态。这个红色状态可就代表着集群有问题,数据的可用性和完整性可能受到了威胁,必须得尽快解决。

问题排查过程

1)查看集群健康值:最先做的就是查看集群的健康值,结果显示集群健康值为red,还有6个未分配的分片。这6个未分配的分片很可能就是导致集群飘红的关键因素,得顺着这个线索继续查下去。

2)查询索引健康值:接着,在Elastic Header中使用_cluster/health?pretty&level=indices这个GET命令,来查看集群中各个索引的状态。这一查,果然找到了处于red状态的索引。从返回的结果中可以看到,这个索引的unassigned_shards(未分配分片)属性值恰好是6,和前面集群显示的未分配分片数量对上了,看来问题就出在这个索引上。

{ "xxx_data_202502": { "status": "red", "number_of_shards": 24, "number_of_replicas": 1, "active_primary_shards": 21, "active_shards": 42, "relocating_shards": 0, "initializing_shards": 0, "unassigned_shards": 6 } }

3)查找异常原因:为了弄清楚这些分片为什么没有分配,又使用了_cluster/allocation/explain命令和GET方法,并且在请求体里设置了前面找到的那个red状态索引,分片数则用第一步集群显示的未分片编号4。

{ "index": "xxx_data_202502", "shard": 4, "primary": true }

得到的响应结果显示,这个分片的current_state(当前状态)是unassigned(未分配),unassigned_info(未分配原因)里的reason(原因)是INDEX_REOPENED(索引重新打开),并且还记录了索引重新打开的时间at以及last_allocation_status(上次分配状态)是no_valid_shard_copy(没有有效的分片副本)。把shard属性换成其他两个未分配分片,得到的结果都差不多。这才想起来,这个索引之前确实是关闭状态,最近才重新打开,看来就是索引重开导致了这些分片分配异常。

{ "index": "xxx_data_202502", "shard": 4, "primary": true, "current_state": "unassigned", "unassigned_info": { "reason": "INDEX_REOPENED", "at": "2025-02-05T05:14:38.153Z", "last_allocation_status": "no_valid_shard_copy" }, "can_allocate": "no_valid_shard_copy", "allocate_explanation": "cannot allocate because a previous copy of the primary shard existed but can no longer be found on the nodes in the cluster", "node_allocation_decisions": [.....// 省略具体节点信息] }

问题解决措施

既然找到了问题所在,就得想办法解决。经过一番研究,决定使用reroute命令对这几个未分配的分片重新进行分配,采用allocate_empty_primary的方式。在ElasticSearch Header里输入/_cluster/reroute命令,使用POST方法,请求体设置如下:

{ "commands": [ { "allocate_empty_primary": { "index": "xxx_data_202502", "shard": 4, "node": "node-1", "accept_data_loss": true } }, { "allocate_empty_primary": { "index": "xxx_data_202502", "shard": 4, "node": "node-2", "accept_data_loss": true } }, ....// TODO 省略其他节点 ] }

这里先针对编号为4的分片,在所有集群节点上都尝试进行分配。执行完这一步后,再对编号为5和16的分片重复上述操作。没想到这么一试,集群健康值居然变成green(绿色)了,代表集群恢复正常状态。同时,负责写入数据的组件写入速率也立马恢复正常,后台再也没有打印积压日志了。

关于操作的一些思考

在使用reroute命令的时候,其实心里还是有点忐忑的。一开始想着把accept_data_loss属性设置为false再执行,毕竟谁也不想因为操作导致数据丢失。结果响应提示说allocate an empty primary for [xxx][4] can result in data loss, Please confirm by setting the accept_data_loss true,意思就是只有把这个属性设置为true才能执行这个操作,感觉这有点像“霸王条款”,但为了解决问题,也只能按照要求设置了。

这次遇到的Elasticsearch集群因索引关闭重开导致飘红的问题,总算是顺利解决了。希望通过我的分享,大家以后遇到类似问题时,能快速定位并解决。要是你也有相关的经验或者疑问,欢迎在评论区一起讨论。