问题起因
自己负责审计日志模块的管理功能,同事突然对我说,写入的日志数据全部不能用了,我立即答复(回怼)“不可能”。
说罢,还是去登录系统查看,能查出数据,只是偶现查询速度特别慢,看控制台,原因是部分请求一直挂起直到超时。
于是登录服务器查看日志,好家伙,果然报错了。
{
"took":60000,
"errors":true,
"items":[
{
"index":{
"_index":"xxx",
"_type":"xxx",
"_id":"ohNNCIABQ5H_8lZrABim",
"status":503,
"error":{
"type":"unavailable_shards_exception",
"reason":"[xxx][4] primary shard is not active Timeout: ..."
}
}
}
]
}
查询挂起,和写入日志数据失败,均为该错误引起,这哪能忍,直接开干。
Round 1
错误原因也写的很清楚了,主分片不可用。
于是查看集群健康状态
//request
{{host}}/_cat/indices
//response
{
"error": {
"root_cause": [
{
"type": "security_exception",
"reason": "current license is non-compliant for [security]",
"license.expired.feature": "security"
}
],
"type": "security_exception",
"reason": "current license is non-compliant for [security]",
"license.expired.feature": "security"
},
"status": 403
}
淦,第一反应就是之前加入X-Pack插件时,说过该插件需要付费证书来授权,第一次申请可以免费试用一个月,到期后部分功能会受限。
经过一番查阅资料,得到结果需要如下操作方可接触限制:
1、到Elasticsearch官方申请免费证书;
2、将证书PUT到受限的服务器以将到普通版本;
该方法也就是放弃使用X-Pack的安全功能,回退到普通功能。
于是又是一顿如虎的操作
//申请并下载好证书
{
"license":{
"uid":"xxx",
"type":"basic",
"issue_date_in_millis":1649376000000,
"expiry_date_in_millis":1680998399999,
"max_nodes":100,
"issued_to":"hoew",
"issuer":"Web Form",
"signature":"xxx",
"start_date_in_millis":1649376000000
}
}
//将证书PUT到受限服务器
{{host}}/_xpack/license' -d @my.json
//却得到如下结果
{
"error": {
"root_cause": [
{
"type": "illegal_argument_exception",
"reason": "Installing basic licenses is no longer allowed. Use the POST /_xpack/license/start_basic API to install a basic license that does not expire."
}
],
"type": "illegal_argument_exception",
"reason": "Installing basic licenses is no longer allowed. Use the POST /_xpack/license/start_basic API to install a basic license that does not expire."
},
"status": 400
}
看起来就是PUT /_xpack/license方法已经废弃了,需要使用POST /_xpack/license/start_basic方法来进行。那还等什么呢,改了调用呗。
Round 2
经过上回合的折腾,总算把证书问题解决了,这下再次调用GET /_cat/indices得到如下信息
red open xxx xxx 5 0 0 0 1.2kb 1.2kb
red open xxx xxx 5 0 3975 0 4.7mb 4.7mb
yellow open xxx xxx 5 0 0 0 1.2kb 1.2kb
...
总之就是好一片红黄交错的胜景,那我们进一步看看是什么原因导致节点的健康状态为red/yellow,于是我们看具体的分片情况
//请求分片情况
GET {{host}}/_cat/shards
//得到如下响应
xxx 1 p STARTED 367523 60.4mb 10.240.50.103 node-1
xxx 3 p UNASSIGNED 366494 60.1mb 10.240.50.103 node-1
...
说明这些不健康索引的分片没有都启动起来。当时因为天气炎热,到这步有点冲昏头脑了,折腾了好久,最后突然想到之前该服务器启动ES的时候报存储空间不足,于是思考有没可能是因为存储空间满了导致的呢。
查看错误原因GET {{host}}/_cluster/allocation/explain,得到如下错误信息
cannot allocate because allocation is not permitted to any of the nodes
于是尝试清除服务器空间
-rw-r--r--. 1 mysql mysql 14514122752 Dec 30 09:28 mysqld.log
这也日志文件也忒大了,于是将该日志备份到其他未满的分区后,将该日志文件清空。
其实后来据非官方信息了解到,当剩余空间小于10%
时,分片无法成功启动。
再次重启ES,以为胜利的曙光已经在召唤了,哪成想…
Round 3
节点还是一片红黄交错,这次强行清醒了,虽然现象一样,但原因可能不一样,于是再次查看错误原因
failed shard on node [xxx]: failed recovery, failure RecoveryFailedException[[xxx][1]: Recovery failed on {node-1}{xxx}{xxxlA}{x.x.x.x}{x.x.x.x:9300}{ml.machine_memory=25334550528, xpack.installed=true, ml.max_open_jobs=20, ml.enabled=true}]; nested: IndexShardRecoveryException[failed to recover from gateway]; nested: AccessDeniedException[/xx/elasticsearch/data/nodes/0/indices/xxx/1/index/_23b.fdt];
好家伙,访问拒绝,熟悉的味道啊。但怎么产生的呢,脑海中立马想到原因可能是之前有一次启动时用的是root用户造成的。
于是立马去看这个受限文件的权限信息,果不其然,属于root用户
//xx为你的es用户
chown -R xx:xx /xx/elasticsearch/data
走你,翻滚吧,阿信!不好意思,串词了。运行完成后,所有数据文件都具有访问权限了,于是再次重启ES…
Round 4
既然看到了第四回合,那你已经知道,前面的battle都没能彻底解决掉我们的问题,但这里有个小小惊喜的是,red状态的索引都已经没了,现在只剩下yellow状态的了,也就是说截止目前,我们的功能已经是能正常使用了。
于是赶紧让文章开头的那个同事(问题源)来重试,果然,他没有再哔哔了。可本着本农追根溯源的优良精神,怎么能止步于此,我一定要让所有索引都是green才行!
那么还是进一步查看问题原因
the shard cannot be allocated to the same node on which a copy of the shard already exists [[xxx][3], node[xxx], [P], s[STARTED], a[id=xxx]]
错误信息也很明显,就是分片副本不能和分片本身分配到同样的节点上。但这个问题刚开始还是迷惑了我,因为我以为分片多的情况可能刚启动时没分配过来,于是准备通过
index.unassigned.node_left.delayed_timeout
参数来延时分配这些未被分配的分片。
一番操作下来,错误信息不断地变,但是结果却始终没有好转,终于当错误产生循环后,终于意识到方向不对了。
这里补充个小知识,ES的分片副本肯定要和分片本身要分配到不同的节点的,也就说每个主分片的副本数要少于群集中的节点数,也就是我们熟知的NR公式
//N代表节点数,R代表所有索引的最大分片复制因子
N >= R + 1
于是我只需要将副本数量进行控制即可
number_of_replicas
一番操作后,总算一片green了
总结
查资料的过程中,还看到有解决办法让哪个索引为yellow/red直接将该索引DELETE即可。WTF?如果解决不了问题就解决提出问题的人吗?
其实总结下来就一句话,遇事不着急,细细看日志,万事必有因,逐破自搞定!(强行银湿一手[doge])