ElasticSearch - 新老選主算法對比

1. 7.X之前的選主流程

Zen Discovery

採用Bully算法,它假定所有節點都有一個唯一的ID,使用該ID對節點進行排序。任何時候的當前Leader都是參與集羣的最高ID節點。該算法的優點是易於實現。但是,當擁有最大ID的節點處於不穩定狀態的場景下會有問題。例如,Master負載過重而假死,集羣擁有第二大ID的節點被選爲新主,這時原來的Master恢復,再次被選爲新主,然後又假死
ES 通過推遲選舉,直到當前的 Master 失效來解決上述問題,只要當前主節點不掛掉,就不重新選主。但是容易產生腦裂(雙主),爲此,再通過“法定得票人數過半”解決腦裂問題

 

只有一個 Leader將當前版本的全局集羣狀態推送到每個節點。 ZenDiscovery(默認)過程就是這樣的:

  • 每個節點計算最高的已知節點ID,並向該節點發送領導投票
  • 如果一個節點收到足夠多的票數,並且該節點也爲自己投票,那麼它將扮演領導者的角色,開始發佈集羣狀態。
  • 所有節點都會參數選舉,並參與投票,但是,只有有資格成爲 master 的節點的投票纔有效.

有多少選票贏得選舉的定義就是所謂的法定人數。 在彈性搜索中,法定大小是一個可配置的參數。 (一般配置成:可以成爲master節點數n/2+1)

 

什麼時候開始選主?

  1. 集羣啓動
  2. Master 失效

    非 Master 節點運行的 MasterFaultDetection 檢測到 Master 失效,在其註冊的 listener 中執行 handleMasterGone,執行 rejoin 操作,重新選主.注意,即使一個節點認爲 Master 失效也會進入選主流程

 

Bully算法缺陷

Master假死

Master節點承擔的職責負載過重的情況下,可能無法即時對組內成員作出響應,這種便是假死。例如一個集羣中的Master假死,其他節點開始選主,剛剛選主成功,原來的Master恢復了,因爲原來Master節點的Id優先級最高,又開始一輪選主,重新把原來Master選舉爲Master

爲了解決這個問題,當Master節點假死的時候會去探測是是不是真的掛了,如果不是會繼續推遲選主過程

 

腦裂

當發生網絡分區故障就會發生腦裂,就會出現雙主情況,那麼這個時候是十分危險的因爲兩個新形成的集羣會同時索引和修改集羣的數據。

 

 

如何解決腦裂問題

有一個minimum_master_nodes設置,集羣中節點必須大於這個數字才進行選主,否則不進行,例如10個節點,現在發生網絡分區,3個節點一組,7個節點另外一組,最開始master在3節點那邊

minimum_master_nodes設置5

這個時候,3節點那組,master會判斷有7個節點退出,然後檢查minimum_master_nodes,發現小於配置,放棄master節點身份,重新開始選主,但是因爲minimum_master_nodes配置,無法進行選主

7節點那組,發現master真的涼了,聯繫不上了,開始選主,選出新的Master節點

 

仍然存在的問題

Zen的minimum_master_nodes設置經常配置錯誤,這會使羣集更容易出現裂腦和丟失數據的風險

 

2. 7.X之後的選主流程

7.X之後的ES,採用一種新的選主算法,實際上是 Raft 的實現,但並非嚴格按照 Raft 論文實現,而是做了一些調整。

Raft是工程上使用較爲廣泛分佈式共識協議,是多個節點對某個事情達成一致的看法,即使是在部分節點故障、網絡延時、網絡分區的情況下。

其設計原則如下:

  1. 容易理解
  2. 減少狀態的數量,儘可能消除不確定性

Raft 將問題分解爲:Leader 選舉,日誌複製,安全性,將這三個問題獨立思考。

在 Raft 中,節點可能的狀態有三種,其轉換關係如下:

正常情況下,集羣中只有一個 Leader,其他節點全是 Follower 。Follower 都是被動接收請求,從不發送主動任何請求。Candidate 是從 Follower 到 Leader的中間狀態。

Raft 中引入任期(term)的概念,每個 term 內最多隻有一個 Leader。term在 Raft 算法中充當邏輯時鐘的作用。服務器之間通信的時候會攜帶這個 term,如果節點發現消息中的 term小於自己的 term,則拒絕這個消息,如果大於本節點的 term,則更新自己的 term。如果一個 Candidate 或者 Leader 發現自己的任期號過期了,它會立即回到 Follower 狀態。

Raft 選舉流程爲:

  1. 增加節點本地的 current term ,切換到Candidate狀態
  2. 投自己一票
  3. 並行給其他節點發送 RequestVote RPC(讓大家投他)。

然後等待其他節點的響應,會有如下三種結果:

  1. 如果接收到大多數服務器的選票,那麼就變成Leader
  2. 如果收到了別人的投票請求,且別人的term比自己的大,那麼候選者退化爲follower
  3. 如果選舉過程超時,再次發起一輪選舉

通過下面的約束來確定唯一 Leader(選舉安全性):

  1. 同一任期內,每個節點只有一票
  2. 得票(日誌信息不舊於Candidate的日誌信息)過半則當選爲 Leader

成爲 Leader 後,向其他節點發送心跳消息來確定自己的地位並阻止新的選舉。

當同時滿足以下條件時,Follower同意投票:

  1. RequestVote請求包含的term大於等於當前term
  2. 日誌信息不舊於Candidate的日誌信息
  3. first-come-first-served 先來先得

 

ES實現的Raft算法選主流程

ES 實現的 Raft 中,選舉流程與標準的有很多區別:

  1. 初始爲 Candidate狀態
  2. 執行 PreVote 流程,並拿到 maxTermSeen
  3. 準備 RequestVote 請求(StartJoinRequest),基於maxTermSeen,將請求中的 term 加1(尚未增加節點當前 term)
  4. 並行發送 RequestVote,異步處理。目標節點列表中包括本節點。

ES 實現中,候選人不先投自己,而是直接並行發起 RequestVote,這相當於候選人有投票給其他候選人的機會。這樣的好處是可以在一定程度上避免3個節點同時成爲候選人時,都投自己,無法成功選主的情況。

ES 不限制每個節點在某個 term 上只能投一票,節點可以投多票,這樣會產生選出多個主的情況:

Node2被選爲主:收到的投票爲:Node2,Node3
Node3被選爲主:收到的投票爲:Node3,Node1

對於這種情況,ES 的處理是讓最後當選的 Leader 成功。作爲 Leader,如果收到 RequestVote請求,他會無條件退出 Leader 狀態。在本例中,Node2先被選爲主,隨後他收到 Node3的 RequestVote 請求,那麼他退出 Leader 狀態,切換爲CANDIDATE,並同意向發起 RequestVote候選人投票。因此最終 Node3成功當選爲 Leader。

 

動態維護參選節點列表

在此之前,我們討論的前提是在集羣節點數量不變的情況下,現在考慮下集羣擴容,縮容,節點臨時或永久離線時是如何處理的。在7.x 之前的版本中,用戶需要手工配置 minimum_master_nodes,來明確告訴集羣過半節點數應該是多少,並在集羣擴縮容時調整他。現在,集羣可以自行維護。

 

在取消了discovery.zen.minimum_master_nodes配置後,ES 如何判斷多數?是自己計算和維護minimum_master_nodes值麼?不,現在的做法不再記錄“quorum” 的具體數值,取而代之的是記錄一個節點列表,這個列表中保存所有具備 master 資格的節點(有些情況下不是這樣,例如集羣原本只有1個節點,當增加到2個的時候,這個列表維持不變,因爲如果變成2,當集羣任意節點離線,都會導致無法選主。這時如果再增加一個節點,集羣變成3個,這個列表中就會更新爲3個節點),稱爲 VotingConfiguration,他會持久化到集羣狀態中。

在節點加入或離開集羣之後,Elasticsearch會自動對VotingConfiguration做出相應的更改,以確保集羣具有儘可能高的彈性。在從集羣中刪除更多節點之前,等待這個調整完成是很重要的。你不能一次性停止半數或更多的節點。(感覺大面積縮容時候這個操作就比較感人了,一部分一部分縮)

 

默認情況下,ES 自動維護VotingConfiguration,有新節點加入的時候比較好辦,但是當有節點離開的時候,他可能是暫時的重啓,也可能是永久下線。你也可以人工維護 VotingConfiguration,配置項爲:cluster.auto_shrink_voting_configuration,當你選擇人工維護時,有節點永久下線,需要通過 voting exclusions API 將節點排除出去。如果使用默認的自動維護VotingConfiguration,也可以使用 voting exclusions API 來排除節點,例如一次性下線半數以上的節點。

如果在維護VotingConfiguration時發現節點數量爲偶數,ES 會將其中一個排除在外,保證 VotingConfiguration是奇數。因爲當是偶數的情況下,網絡分區將集羣劃分爲大小相等的兩部分,那麼兩個子集羣都無法達到“多數”的條件。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章