前言
可能你經歷過這些Red.
。。。等等
那ES的Red是神麼意思?
這裡說的red,是指es集群的狀態,一共有三種,green、red、yellow。具體含義:
冷靜分析
從上圖可知,集群red是由於有主分片不可用,這種情況一般是由於節點宕機。
有什麼影響呢?
至少一個主分片(以及它的全部副本)都在缺失中。這意味著你在缺少數據:搜索只能返回部分數據,而分配到這個分片上的寫入請求會返回一個異常。
此時我們可以執行相關的命令進行狀態檢查。
集群節點是否都存在、查看集群狀態。
curl -uelastic:pwd -XGET "http://ip:9200/_cluster/health?pretty"
active_shards 是涵蓋了所有索引的所有分片的匯總值,其中包括副本分片。relocating_shards 顯示當前正在從一個節點遷往其他節點的分片的數量。通常來說應該是 0,不過在 Elasticsearch 發現集群不太均衡時,該值會上漲。比如說:添加了一個新節點,或者下線了一個節點。initializing_shards 顯示的是剛剛創建的分片的個數。比如,當你剛創建第一個索引,分片都會短暫的處於 initializing 狀態,分片不應該長期停留在 initializing 狀態。你還可能在節點剛重啟的時候看到 initializing 分片:當分片從磁碟上加載後,它們會從 initializing 狀態開始。所以這一般是臨時狀態。unassigned_shards 是已經在集群狀態中存在的分片,但是實際在集群裡又找不著。最常見的體現在副本上。比如,我有兩個es節點,索引設置分片數量為 10, 3 副本,那麼在集群上,由於災備原則,主分片和其對應副本不能同時在一個節點上,es無法找到其他節點來存放第三個副本的分片,所以就會有 10 個未分配副本分片。如果你的集群是 red 狀態,也會長期保有未分配分片(因為缺少主分片)。
unassigned_shards原因1
上面說了一種造成 unassigned_shards的原因,就是副本太多,節點太少,es無法完成分片。舉一反三!由於索引的副本是可以動態修改的,那麼,如果在修改時分配的副本數大於節點數目,那麼肯定會有分片是這個狀態。這種情況的解決辦法有兩種: 1、是動態調整一下副本數量。 2、新加入一個節點來平衡。unassigned還有其他原因?
目前集群爆紅,但是所有節點都還在,有點詭異,從集群狀態看,一共是兩個分片有問題,一個正在初始化,一個是unassigned。確定了故障範圍後,我們再來從索引層面、分片層面深入的分析具體原因把。
索引層面分析
再執行
curl -uelastic:pwd -XGET "http://ip:9200/_cluster/health?pretty&level=indices"沒錯,還是這個api,不過值得注意的是level=indices,想必讀者已經心領神會。這個api返回的是一個格式化後的json,如果太長,推薦輸出到一個文本裡面看。
從返回的信息中,我們可以看到,01-04索引目前狀態為red,它有2個分片,0個副本,有一個分片正在初始化,從這個數據可以看出,受影響的是主分片,想到這裡,感到慌不擇路。
分片層面分析
少俠,莫慌!
知道了索引層面的故障信息,我們繼續深究,看看分片層面。
curl -uelastic:pwd -XGET "http://ip:9200/_cluster/health?level=shards"當然,重點還是level=shards,顯示如下:
至此,我們可以得到更多的線索:
索引名:xxx-01-04。分片數量:2。副本數:0。有問題的分片號:0。並且是主分片。分片狀態:initializing。說明正在初始化,自我恢復中。既然是在恢復,那找恢復相關的api,看看。
curl -u elastic:pwd -XGET http://ip:9200/索引名/_recovery?pretty=true
從上圖可以看到,花費了14.1個小時,從translog中恢復!目前進度很是堪憂。配合kibana看一下:
插播一下,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到磁碟,但是性能會比較差。上述摘錄於網際網路,寫得清晰明了,可以參考一下,分析看了日誌也沒有找到其他有用的信息,由於是歷史索引,就將其刪除掉了,雖然沒有定位到根本原因,不過記錄一下排查過程總是好的。
剩下的unassigned分片
解決了一個問題,那麼還剩下一個分片是未分配的,還是從索引層面和分片層面查詢檢查,發現同樣是0號主分片出問題。嘗試手動分配curl -uelastic:pwd -XPOST 'http://ip:9200/_cluster/reroute' -H"Content-Type:application/json" -d '{ "commands" : [ { "allocate_stale_primary" : { "index" : "B_2020-01-05", "shard" : 0, "node" : "SL8u8zKESy6rSHjHO0jEvA" } } ] }'報錯:
No data for shard [0] of index [B_2020-01-05] found on node [SL8u8zKESy6rSHjHO0jEvA]"},"status":400}
嘗試手動分配失敗後,更換思路。擺脫掉各種複雜的查詢API,使用es為我們提供的一個Explain API,它會解釋為什麼分片沒有分配,解決問題之前,先診斷診斷。curl -uelastic:pwd -XGET "http://ip:9200/_cluster/allocation/explain" -H"Content-Type:application/json" -d '{ "index": "B_2020-01-05", "shard": 0, "primary": true}'
看上述錯誤,分片被鎖住了,嘗試分配,但是被拒絕,手動分配時,可以指定"acceptdataloss" : true。但這樣會導致數據完全丟失。這種情況一般出現在有結點短暫離開集群,然後馬上重新加入,並且有線程正在對某個shard做bulk或者scroll等長時間的寫入操作。等結點重新加入集群的時候,由於shard lock沒有釋放,master無法allocate這個shard。 通常/cluster/reroute?retryfailed=true可以解決問題,如果按照你說的依然無法解決,可能還有其他原因導致鎖住該shard的線程長時間操作該shard無法釋放鎖(長時間GC?)。如果retryfailed無法解決問題,可以嘗試一下allocatestale_primary,前提是需要知道這個shard的primary在哪個結點上。實在解決不了,又不想丟數據,還可以重啟一下該結點,內存鎖應該可以釋放。執行集群reroute命令:
curl -XPOST "http://ip:9200/_cluster/reroute?retry_failed=true"
再看分片狀態:
此時集群已經恢復Green。大功告成。總結
一、遇到集群Red時,我們可以從如下方法排查:
集群層面:/_cluster/health。索引層面:/_cluster/health?pretty&level=indices。分片層面:/_cluster/health?pretty&level=shards。看恢復情況:/_recovery?pretty。二、有unassigned分片的排查思路
_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,將目前可用的數據導入:POST _reindex{"source": {"index": "a_index"},"dest": {"index": "aindexcopy","op_type": "create"}}
刪除a_index索引,這個必須要先做,否則別名無法添加.curl -XDELETE 'http://xxxx:9200/a_index'
創建aindexcopy索引
curl -XPUT 『http://xxxx:9200/a_index_copy/『 -d 『{「settings」:{ 「index」:{ 「number_of_shards」:3, 「number_of_replicas」:2 } }}通過reindex api將aindex數據copy到aindex_copy。
POST _reindex{"source": { "index": "a_index" }, "dest": { "index": "a_index_copy", "op_type": "create" }}刪除a_index索引,這個必須要先做,否則別名無法添加
curl -XDELETE 'http://xxxx:9200/a_index'給aindexcopy添加別名a_index
curl -XPOST 'http://xxxx:9200/_aliases' -d '{ "actions": [ {"add": {"index": "a_index_copy", "alias": "a_index"}} ]}'四、translog總結
translog在節點有問題時,能夠幫助阻止數據的丟失設計目的:
1、幫助節點從失敗從快速恢復。
2、輔助flush。避免在flush過程中數據丟失。
以上就是這篇筆記的所有內容,希望能幫助到你。
歡迎來公zhong號【俠夢的開發筆記】 一起交流進步