Raft 算法之領導人選舉

Raft 算法之領導人選舉

Raft 論文地址:https://ramcloud.atlassian.ne... 算法

Raft論文中分爲三塊:安全

  • 領導選舉
  • 日誌複製
  • 安全性

本文中主要介紹領導人選舉服務器

Raft中的節點狀態

Raft中的節點有三種狀態:網絡

  • 領導人狀態:Leader
  • 跟隨者狀態:Follower
  • 候選人狀態:Candidate

每個節點都是一個狀態機,Raft會根據當前的心跳,任期等狀態來進行狀態的遷移轉化,就以下圖所示:併發

raft-role.png

首先,在Raft節點啓動的時候,全部任務都是Follower狀態, 由於此時沒有Leader,全部Follower都在固定的超時時間內都收不到來自Leader的心跳,從而變成了Candidate狀態,開始選舉Leaderspa

當節點處於Candidate狀態的時候,會併發的向全部的節點發出請求投票請求RequestVote(後面章節會向詳細介紹),在Candidate狀態下,節點可能會發生三種狀態的遷移變化:.net

  • 開始下一輪新的選舉:發出的投票請求在固定時間內沒有收到其餘節點的響應,或者是收到響應(或者贊成投票)的節點數量沒有達到 N/2+1,那麼選取超時,進入下一輪選舉
  • 選舉成功,成爲新的Leader:若是選舉過程當中收到大於N/2+1數量的節點的投票,那麼選舉成功,當前的節點成爲新的Leader
  • 成爲Follower:若是選舉過程當中收到來及其餘節點的Leader心跳,或者是請求投票響應的Term大於當前的節點Term,那麼說明有新任期的Leader

若是節點選舉成功,成爲了Leader,那麼Leader將會在固定週期內發送心跳到全部的節點,可是若是心跳請求收到的響應的Term大於當前節點的Term,那麼當前節點的就會成爲Follower。好比Leader節點的網絡不穩定,掉線了一段時間,網絡恢復的時候,確定有其餘節點被選爲了新的Leader,可是當前節點在掉線的時候並無發現其餘節點選爲Leader,仍然發送心跳給其餘節點,其餘節點就會把當前的新的Term響應給已通過時的Leader,從而轉變成Follower日誌

領導人選舉

整個集羣必需要在丟包,亂序,延時等諸多不穩定因素的狀況下,可以選舉出惟一一個Leadercode

請求投票RPC

就如上文中提到的,若是Follower在必定時間內沒有收到心跳請求,那麼將會切換到Candidate狀態,開始一輪新的選取,選舉過程當中會向集羣中的全部節點發送請求投票的RPCblog

RPC請求參數:

  • term:當前候選人的任期號
  • candidateId:候選人的Id
  • lastLogIndex:候選人的最後日誌條目索引值
  • lastLogTerm:候選人的最後日誌條目的任期號

其中lastLogIndexlastLogTerm用來判斷候選人的日誌是否和服務器的日誌同樣新(後文中會解釋),必需要至少同樣新才能投票。

RPC響應值:

  • term:被請求節點的任期號
  • voteGranted:是否贊成投票給候選人

Candidate發送請求投票RPC

Candidate什麼時候發送請求投票RPC?

若是Leader發生異常,那麼基本上全部的Follower在同一時間切換爲Candidate,並同時發出請求投票的RPC,那麼就有可能致使選票被均衡的瓜分,從而須要從新發起新一輪的投票。爲了不選票被瓜分的問題,選舉超時的是能夠能夠從一個固定的區間(例如150-300毫秒)隨機選擇。

Candidate如何發送投票RPC?
  1. 自增當前節點的任期號
  2. 給本身投票
  3. 重置選舉超時計時器
  4. 發送請求投票的RPC給其餘服務器
節點收到請求投票的RPC該如何處理?
  1. 判斷當前的Term的和請求投票參數中的Term

    • 若是當前的Term > 請求投票參數中的Term,那麼拒絕投票(設置voteGrantedfalse),並返回當前的Term
    • 不然就更新當前Term爲請求投票參數中的Term, 並將自身狀態切換成Follower
  2. 檢測當前節點的投票狀態:

    • 若是當前的節點沒有給任何其餘節點投過票,或者是已經投過票給當前節點,那麼繼續檢測日誌的匹配狀態(步驟3)
    • 不然,那麼拒絕投票(設置voteGrantedfalse), 由於一個節點在一個任期內不能同時投票給多個節點
  3. 檢測候選人的日誌是否至少比當前節點的日誌新,經過比較候選人的lastLogIndexlastLogTerm和當前節點的日誌,確保新選舉出來的Leader不會丟失已經提交的日誌:

    • 若是日誌匹配,即當前的任期和候選人的任期相同,且候選人的日誌長度比當前的日誌長度 或者 候選人的任期比比當前節點的任期高,那麼就爲候選人投票(設置votedGrantedtrue),併成爲Follower
    • 不然,那麼就拒絕投票(設置voteGrantedfalse
Candidate收到請求投票的響應該如何處理?

每個候選人在每個任期內都會發出一輪投票請求,若是在指定時間內,收到大於N/2+1個節點的贊成投票的響應,那麼說明投票成功,晉升爲Leader

由於在整個投票過程當中,假設網絡是不穩定的,那麼就有可能致使投票請求和請求的響應丟失,亂序,延時等,從而致使收到和當前任期不相匹配的響應,因此若是收到和當前任期不匹配的響應,那麼就直接丟棄不處理。

完整的處理流程以下:

  1. 檢查響應的Term是否大於當前候選人的Term

    • 若是是,那麼說明有其餘節點開始了新一輪的選舉或者是有新的Leader被選舉出來,那麼就把當前節點從Candidate切換爲Follower狀態,並更新當前節點的Term
    • 不然,進行步驟2
  2. 檢查響應的Term是否和當前的節點的Term是否相等:

    • 若是相等,那麼說明在指定時間內收到了投票請求的響應,那麼就進行步驟3
    • 不然說明這是一個過時的投票請求響應,直接丟棄
  3. 檢查響應是否贊成投票:

    • 若是贊成,那麼增長當前任期的贊成投票節點數量,並檢查贊成投票的節點數量大於 N/2+1,那麼就切換爲Leader
    • 若是不一樣意,多是日誌不匹配,由於Leader的日誌至少要比Follower的日誌新

領導人選舉的安全性

從上文的請求投票RPC的處理流程中得知,Leader不是隨便選一個節點均可以成爲的,若是候選人不知足要求,那麼其餘節點就不會給候選人投票。

若是集羣中的任何一個節點不通過判斷就能成爲Leader,那麼將會發生什麼?這種狀況可能致使已經被提交的日誌被覆蓋,若是狀態機已經Apply了被覆蓋的日誌,將會致使不一致的結果。因此爲了選舉的安全性,Raft添加了如下的限制:

  1. Leader不會覆蓋本身的任何日誌,Follower嚴格按照Leader的日誌進行復制(必要時強行覆蓋)
  2. 選舉Leader的時候,Candidate的日誌至少要比當前節點新(這個「新」稍後解釋),不然就拒絕投票;由於已經提交的日誌確定是存在大於等於N/2+1個節點上的,而投票至少也須要N/2+1個節點贊成,因此整個投票過程當中確定會有包含有全部已經提交日誌的節點存在的。

上文中的「新」就是:即當前的任期和候選人的任期相同,且候選人的日誌長度比當前的日誌長度 或者 候選人的任期比比當前節點的任期高

相關文章
相關標籤/搜索