es集群狀態red
問題描述
公司有一套kibana日志收集系統,組合方式為filebeat+elasticsearch+kibana,elasticsearch使用三台服務器組合成集群。近期公司的zabbix服務器持續告警某台服務器cpu使用率在80%以上,
登錄服務器首先查看是哪個服務器對cpu占用過多,查看是因為es導致。
排查思路
- 針對es集群占用cpu使用率過高問題
# 因es集群僅作為kibana日志收集使用,所以使用es-head首先查看集群狀態
- 針對es集群red狀態問題
# es集群的幾種狀態
green:所有主分片和副本都可用
yellow:所有主分片都可用,但不是所有副本分片都可用
red:不是所有主分片都可用,這意味着缺少數據:搜索只能返回部分數據,而分配到這個分片上的寫入請求會返回一個異常。
# 查看es集群當前狀態(當前集群都在線,沒有問題)
[root@VM-30-28-centos logs]# curl -s 172.31.30.28:9200/_cat/nodes
172.31.30.28 63 96 4 0.02 0.16 0.36 dilm - VM-30-28-centos
172.31.30.88 20 98 9 0.32 0.50 0.56 dilm * VM-30-88-centos
172.31.30.48 60 97 9 0.91 0.73 0.83 dilm - VM-30-48-centos
疑問:雖然處於red狀態,但是集群狀態沒有問題
# 1.查看系統最大打開文件描述符數是否夠用
[root@VM-30-28-centos logs]# df -i # 使用都在百分之一左右,絲毫不影響
Filesystem Inodes IUsed IFree IUse% Mounted on
devtmpfs 2030545 346 2030199 1% /dev
tmpfs 2033272 7 2033265 1% /dev/shm
tmpfs 2033272 469 2032803 1% /run
tmpfs 2033272 16 2033256 1% /sys/fs/cgroup
/dev/vda1 3276800 65778 3211022 3% /
tmpfs 2033272 1 2033271 1% /run/user/0
/dev/vdb1 32768000 161045 32606955 1% /opt
查看當前健康狀態,發現未分配分片數居然達到了三千多,並且集群中所有活躍的分片數和主分片數達成了一致,也就是未分配的都是副本分片,主分片處於活躍狀態,
由於災備原則,主分片和其對應副本不能同時在一個節點上,es無法找到其他節點來存放第三個副本的分片,所以導致了集群處於red狀態
但是為什么會出現es無法找到其他節點來存放第三個副本分片呢?
原因如下:
① 副本太多,節點太少,es無法完成分片
解決方式:1. 減少副本數 2. 增加節點數
② 分片被鎖住了
解決方式: 嘗試分配,或者手動分配, 可以指定"accept_data_loss" : true。但這樣會導致數據完全丟失。
③ 有節點短暫離開集群,然后重新加入,並且有線程對某個分片做bulk或者scroll等長時間寫入操作,等節點重新加入集群,由於分片 lock滅有釋放,master無法分配這個分片,
通常/_cluster/reroute?retry_failed=true可以解決問題,如果依然無法解決,可能還有其他原因導致鎖住該shard的線程長時間操作該shard無法釋放鎖(長時間GC?)。 所以有可能是索引過大導致。
# 查看所有索引的狀態,大小等
curl -XGET 'http://172.31.30.28:9200/_cat/indices?v'
這里的截圖並不完整,當時有red狀態的索引和yellow狀態的索引,這里的解決辦法直接將red狀態索引刪除處理
刪除red狀態索引方式,但我這里僅作為日志索引,所以影響不大,刪除需要結合實際情況考慮
curl -XGET 'http://172.31.30.28:9200/_cat/indices?v'|grep 'red' |awk '{print $3}'|xargs -i curl -XDELETE "http://172.31.30.88:9200/{}"
后續查看es-head狀態,es集群狀態從red轉為yellow,刪除red索引后個別索引從yellow狀態變為green狀態
總結:
遇到集群Red時,我們可以從如下方法排查 :
- 集群層面:curl -s 172.31.30.28:9200/_cat/nodes 或者 GET _cluster/health
- 索引層面:GET _cluster/health?pretty&level=indices
- 分片層面:GET _cluster/health?pretty&level=shards
- 恢復情況:GET _recovery?pretty
有unassigned分片的排查思路 :
- 先診斷:GET _cluster/allocation/explain
- 重新分配: /_cluster/reroute
實在無法分配:
索引重建:
① 新建備份索引:
curl -XPUT ‘http://xxxx:9200/a_index_copy/‘ -d ‘{ “settings”:{ “index”:{ “number_of_shards”:3, “number_of_replicas”:2 } } }
② 通過reindex api將a_index數據copy到a_index_copy:
POST _reindex { "source": { "index": "a_index" }, "dest": { "index": "a_index_copy", "op_type": "create" } }
③ 刪除a_index索引,這個必須要先做,否則別名無法添加
curl -XDELETE 'http://xxxx:9200/a_index'
④ 給a_index_copy添加別名a_index
curl -XPOST 'http://xxxx:9200/_aliases' -d ' { "actions": [ {"add": {"index": "a_index_copy", "alias": "a_index"}} ] }'
translog總結
translog在節點有問題時,能夠幫助阻止數據的丟失
設計目的:
1、幫助節點從失敗從快速恢復。
2、輔助flush。避免在flush過程中數據丟失。
插播一下,translog的知識
- 我們把數據寫到磁盤后,還要調用fsync才能把數據刷到磁盤中,如果不這樣做在系統掉電的時候就會導致數據丟失,這個原理相信大家都清楚,elasticsearch為了高可靠性必須把所有的修改持久化到磁盤中。
- 我們的數據先寫入到buffer里面,在buffer里面的數據時搜索不到的,同時將數據寫入到translog日志文件之中。如果buffer快滿了,或是一段時間之后,就會將buffer數據refresh到一個新的OS cache之中。
- translog的作用:在執行commit之前,所有的而數據都是停留在buffer或OS cache之中,無論buffer或OS cache都是內存,
一旦這台機器死了,內存的數據就會丟失,所以需要將數據對應的操作寫入一個專門的日志文件之中。- 一旦機器出現宕機,再次重啟的時候,es會主動的讀取translog之中的日志文件數據,恢復到內存buffer和OS cache之中。
整個commit過程就叫做一個flush操作- 其實translog的數據也是先寫入到OS cache之中的,默認每隔5秒之中將數據刷新到硬盤中去,也就是說,
可能有5秒的數據僅僅停留在buffer或者translog文件的OS cache中,如果此時機器掛了,
會丟失5秒的數據,但是這樣的性能比較好,我們也可以將每次的操作都必須是直接fsync到磁盤,但是性能會比較差。
附:
查看es狀態
# 附,命令方式查看es:
curl -uelastic:pwd -XGET "http://172.31.30.28:9200/_cluster/health?pretty"
{
"cluster_name" : "es-for-joyuai-log", # es集群名稱
"status" : "green", # es集群狀態
"timed_out" : false, # 是否出現超時
"number_of_nodes" : 3, # es節點數
"number_of_data_nodes" : 3, # es數據節點數
"active_primary_shards" : 1167, # 集群中所有活躍的主分片數
"active_shards" : 2334, # 集群中所有活躍的分片數
"relocating_shards" : 0, # 當前節點遷往其他節點的分片數量,通常為0,當有節點加入或者退出時該值會增加
"initializing_shards" : 0, # 正在初始化的分片
"unassigned_shards" : 0, # 未分配的分片數,通常為0,當有節點加入或者退出時該值會增加。
"delayed_unassigned_shards" : 0, # 延遲未分配的分片數
"number_of_pending_tasks" : 0, # 是指主節點創建索引並分配shards等任務,如果該指標數值一直未減小代表集群存在不穩定因素
"number_of_in_flight_fetch" : 0,
"task_max_waiting_in_queue_millis" : 0,
"active_shards_percent_as_number" : 100.0 # 集群分片的可用性百分比,如果為0則表示不可用
}
腳本刪除30天前的日志索引
#!/bin/bash
#刪除ELK30天前的日志
DATE=`date -d "30 days ago" +%Y.%m.%d`
curl -s -XGET http://172.31.30.88:9200/_cat/indices?v| grep $DATE | awk -F '[ ]+' '{print $3}' >/tmp/elk.log
for elk in `cat /tmp/elk.log`
do
curl -XDELETE "http://172.31.30.88:9200/$elk"
done