Raft ABC之二

基於Raft 的分佈式一致性協議是構建很多分佈式服務的基礎,某種程度上它充當了心臟的角色,爲此有必要對Raft 的一些難點進行深入理解。

正確理解commited

一個常見的誤解就是複製到多數副本的就可以視作commited, 其實還不夠。缺少必須已經執行了對應的操作這個步驟。個人理解在實際 Raft使用過程中,就是存在某個Raft log 在append到多個副本的瞬間宕機了,由於還沒有執行on_apply() ,其實還沒有向上層用戶ACK 這條日誌已經成功。
因此這條日誌可以truncate, 也可以後續隨着後續的log commited 之後自己也被commited。

正確理解選主的幾個比較條件

爲什麼需要把距離上次主更新的時間和election_timeout 比較

這個比較大規則如下:
某個follower 收到 vote 請求之後,會計算出收到請求的時間和上次收到主心跳的時間間隔,然後把這個間隔和一個約定的較小時間進行比較。如果前者還小(此時說明還有其他節點長時間沒有收到主的心跳,發起了vote),拒絕這次vote 請求,否則投贊成票。

考慮三個互聯互通的IDC A、B、C,B是主副本,如果由於某種原因B、C網絡不通了,如果沒有上面限制,B發起帶有最高term信息的vote請求,A會同樣vote請求,這樣主就從B變成了C。同理,過了以後,主又很可能從C再變成B。如此 反覆循環,整個複製組上沒有辦法提供持續穩定的主。

爲什麼需要使用LastLogIndex 和LastLogTerm進行新舊log的比較

這個規則如下:
某個follower 收到 vote 請求之後,在current term和請求中的term 相等的情況下:需要使用當前節點的LastLogIndex 、LastLogTerm和請求中的LastLogIndex、LastLogTerm進行比較,如果前者大,則拒絕請求;如果後者大,則同意請求。

考慮下,爲啥要這樣?還是考慮上面三個互聯互通的IDC A、B、C,B是主副本,如果由於某種原因B、C網絡不通了,C是劃分節點。當網絡劃分之後,C的current Term是最高的,它很可能發起vote,這樣把B Stepdown了,A和B的currentTerm 提升了;可是因爲C的LogIndex很低,它發到A和B的Vote 請求,在同A、B的Last LogIndex  比較時發現自己太小,而沒法拿到A、B的信任票,因此Vote失敗。隨後A或B再發起Vote , 就是用最高的Term(C的Term+1 )、最新的LastLogIndex(A 或B的LastLogIndex),一定會選主成功,並且擁有最新的數據。

正確理解成員變更的原理

Raft採用的成員變更單策略相對簡單,每次只增刪一個節點,這樣就不會出現兩個多數集合,不會造成決議衝突的情況。按照如下規則進行處理:
  • Leader收到AddPeer/RemovePeer的時候就進行處理,而不是等到committed,這樣馬上就可以使用新的peer set進行復制AddPeer/RemovePeer請求。
  • Leader啓動的時候就發送AddPeer請求,防止上一輪AddPeer沒有完成commit。
  • Leader在刪除自身節點的時候,會在RemovePeer被Committed之後,進行關閉。

按照上面的規則,可以實現安全的動態節點增刪,因爲節點動態調整跟Leader選舉是兩個並行的過程,節點需要一些寬鬆的檢查來保證選主和AppendEntries的多數集合:

  • 節點可以接受不是來自於自己Leader的AppendEntries請求
  • 節點可以爲不屬於自己節點列表中的Candidate投票

爲了避免同時有兩個節點變更正在進行,在有未committed的change正在進行的時候,不允許進行節點變更。節點變更有一個問題,對一個只有兩個節點的Cluster,發起RemovePeer。這個時候一個節點掛掉,另外一個節點沒有收到RemovePeer請求,這樣系統將停止工作。因此強烈建議集羣節點數>=3個。

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