1、問題描述
早上醒來發現手機有很多ES狀態為red的告警,集群就前幾天加了幾個每天有十多億記錄的業務,當時估算過磁盤容量,應該是沒有問題的,但是現在集群狀態突然變成red了,這就有點懵逼了。
2、查找問題原因
沒辦法,問題出來了,只好查找問題的原因了。
先看看集群的狀態
curl -XGET 'http://unknow.com/_cat/health?v&pretty'
epoch timestamp cluster status node.total node.data shards pri relo init unassign pending_tasks max_task_wait_time active_shards_percent 1504509540 15:19:00 xxx-es-cluster red xx xx xxxx xxxx 2 0 10 0 - 99.99%
從上可看出,集群狀態為red,說明有primary shard丟失了,看后面顯示有10個shards是unassign,看來問題就出在這里了。
再看看是哪些索引有問題
curl -XGET 'http://unknow.com/_cat/indices?v&pretty'
發現有幾個索引的狀態為red,明顯是unassign shard導致的。
現在具體看看哪些shard是unassign
curl -XGET 'http://unknow.com/_cat/shards?v&pretty'
找到unassign的shard,再看unassign的原因,這個ES有個比較好的cluster allocation explain api,可以直接查看unassign的原因,通過該api查到:設備上沒有空間
查看各結點的存儲使用情況
現在只能看各結點的容量使用情況了,再來個api
curl -XGET 'http://unknow.com/_cat/allocation?v&pretty'
這個可以查看每個結點的磁盤使用情況,奇怪的是並沒有結點的存儲滿了,最高的也使用不到70%。
至此,雖然shard unsigned的原因找到了,就是磁盤滿導致的,但是深層次的原因還沒有找到。

3、處理方案
既然原因找到了,那就先恢復吧,恢復很簡單,可以參考ES提供的reroute api
因為這里主要是primary shard unassigned,恢復的命令如下:
curl -XPOST 'http://unknow.com/_cluster/reroute?retry_failed=5&pretty' -d ' { "commands" : [ { "allocate_stale_primary" : { "index" : "myindex", "shard" :0, "node" : "node-ip", "accept_data_loss" : true } }] }'
注意:這里用的是allocate_stale_primary,官網描述如下:
Allocate a primary shard to a node that holds a stale copy. Accepts the index and shard for index name and shard number, and node to allocate the shard to. Using this command may lead to data loss for the provided shard id. If a node which has the good copy of the data rejoins the cluster later on, that data will be overwritten with the data of the stale copy that was forcefully allocated with this command. To ensure that these implications are well-understood, this command requires the special field accept_data_loss to be explicitly set to true for it to work.
4、深層原因
問題是解決了,集群狀態也恢復成green了,但是最終原因還是沒有找到,說不定明天又會收到一堆告警了
先看看ES的日志
跑到master結點上看了下日志,分別看到這種日志
[2017-09-03T02:52:58,609][WARN ][o.e.c.r.a.d.DiskThresholdDecider] [master-node] after allocating, node [szTykZvTTQ-8gskQMAK4UQ] would have more than the allowed 10% free disk threshold (4.7% free), preventing allocation
[2017-09-03T02:53:28,732][WARN ][o.e.c.r.a.DiskThresholdMonitor] [master-node] high disk watermark [90%] exceeded on [szTykZvTTQ-8gskQMAK4UQ][data-node][/data4/search/data/nodes/0] free: 0b[0%], shards will be relocated away from this node
[2017-09-03T02:54:58,659][WARN ][o.e.c.a.s.ShardStateAction] [master-node] [myindex][0] received shard failed for shard id [[myindex][0]], allocation id [xff7GrobTBuf6w3XplxR7Q], primary term [0], message [shard failure, reason [merge failed]], failure [NotSerializableExceptionWrapper[merge_exception: java.io.IOException: 設備上沒有空間]; nested: IOException[設備上沒有空間];
從上可以很清楚的看出,索引的shard做merge的時候,磁盤沒有空間了,導致merge failed,最終導致shard failure,表現就是 shard unssigned
為啥會磁盤滿?
按理說ES集群會自動做均衡的,不應該會出現某個盤滿的情況,關於ES集群的Cluster Level Shard Allocation和Disk-Based Shard Allocation,大家可以自己看一下。
雖然ES集群有這些balance和rebalance的策略,但是都是基於shard的,shard是ES最基本單位,一個shard只能分配到一個磁盤上,那是不是shard的大小不均造成的呢?通過查看集群shard的api可以看到每個shard的存儲大小:
curl -XGET 'http://unknow.com/_cat/allocation?v&pretty'
對結果進行排序后發現,還真的有一些索引的shard會很大,最大的已經達到了100多G,我的天啊,怎么會變這么大,之前都差不多只有10G,后面查看業務的數據量,原來是業務增長導致的。
這個其實還不至於使磁盤滿,因為我當天的索引為了加快索引速度,都是設置的0副本,在第二天凌晨的時候會把它設置成1副本,由於結點的每個盤還不到300G(坑爹的機器配置),集群在復制那種100多G的分片的時候很容易就導致某個磁盤滿了。
5、最終解決
增加shard數
道理很簡單,增加shard后,使每個shard的大小減少到10G左右,由於ES集群是基於shard來進行balance和rebalance的,且shard不能再分,因此減小shard的大小可以減小磁盤滿的概率。
先把大的分片移到剩余空間大的結點,再增加副本數
如果集群總的剩余空間很足,只是極個別的盤滿了,可以把大的shard遷移到磁盤大、剩余空間多的結點上,這樣來規避磁盤滿的風險。
6、總結
通過這一折騰,了解了shard的allocation,同時隨着集群的數據的增長,可以避免后面踩更大的坑。另外,集群的運營和監控也很重要。
文章可以轉載, 但必須以超鏈接形式標明文章原始出處和作者信息
鏈接:https://www.jianshu.com/p/443cf6ce87d5
來源:簡書