Raft理論是分佈式數據一致性算法,爲了便於理解Raft算法分成了4個部分:
-
Leader選舉
-
日誌複製
-
成員變更
-
日誌壓縮
此係列文章先來分析Raft Leader選舉的原理及實現,在後續《分佈式數據複製》的系列文章中,我們再回過頭來實現Raft算法的其他功能。
Leader選舉:
選舉原則:典型的投票選舉算法(少數服從多數),也就是說,在一定週期內獲得投票最多的節點成爲主節點。
節點角色:
-
Leader,主節點,一個任值週期內只有一個主節點。
-
Candidate,候選節點,集羣中沒有Leader時發起投票,進行選舉。
-
Follower,跟隨節點,即主節點的從節點。
消息類型:
-
Vote,投票消息
-
Heartbeat,心跳消息,Follower接收Leader的心跳消息,重置選舉計時器。
選舉過程:
-
節點剛啓動時,默認是Follower狀態。
-
啓動之後,開啓選舉超時定時器,節點切換到Candidate狀態,發起選舉請求。
-
當Candidate狀態的節點,接收到超過半數的投票,則成爲主節點,切換到Leader狀態。每一輪選舉,每個節點只能投一次票。
-
Leader狀態的節點向其他節點發送心跳消息,其他Candidate狀態的節點切換回Follower狀態,並重置選舉超時定時器。
-
Leader節點收到更高任期號的消息,切換到Follower狀態。這種情況主要發生在有網絡分區時。
假設有5個節點,選舉過程如下圖:
-
初始5個節點爲Follower狀態,任職週期爲1(Term=1)。
-
節點切換爲Candidate狀態,開啓選舉定時器,任值週期加1(Term=2)。先爲自己投票,然後向其他節點請求投票。
-
得票數超過節點半數的節點,切換爲Leader狀態,並向其他4個節點發送心跳消息。其他4個節點切換爲Follower狀態。
網絡分區:
下面看看,當發生網絡分區時,節點狀態如何切換。如下圖:
網絡發生A、B兩個分區,A分區的3個節點繼續提供服務。B分區的2個節點由於沒有收到Leader節點的心跳消息,在選舉定時器超時後,切換到Candidate狀態,開始進行投票選舉,任職週期加1(Term=3)。
當網絡恢復後,A分區節點的任值週期(Term=2)比B分區節點的任值週期(Term=3)小,因此A分區的節點切換成Follower狀態,5個節點開始進行投票選舉,最終選舉出Leader節點。
問題:如何避免網絡恢復後,不發生切主?
如上圖,B分區的2個節點由於永遠得不到超過半數的投票,所以任職週期不斷累加。當網絡恢復後,原來的Leader由於任職週期小,切換爲Follower狀態,集羣重新選主。
如何避免重新選主,將投票階段分拆成兩階段,即預投票階段和投票階段。
預投票階段:任職週期不累加,選出得票數過半的節點。
投票階段:由在預投票階段選出的節點發起投票請求,任職週期累加,最終選出主節點。
這樣,B分區2個節點的任值週期就會小於等於原Leader的任值週期,當網絡恢復後就不會重新選主。
開源軟件應用:Go語言編寫的etcd組件,是一個高可用,強一致的數據存儲倉庫,就是實現了Raft算法的選主和數據一致性,Kubernetes的選主就是使用的etcd組件。
總結:
Raft的選舉算法,節點有三個角色:Leader、Candidate、Follower。有兩種通信消息:投票消息,心跳消息。由選舉定時器開啓任值週期,在任值週期內得票過半的節點成爲主節點。
優點是算法複雜度低,易於實現,主節點穩定,不會輕易發生切主。缺點是集羣內節點需要全通信,通信量比較大。
Raft算法的Leader選舉原理講解完了,下一篇文章《分佈式選舉-Raft算法-2 Leader選舉 代碼實現》我們來具體看看如何用代碼實現分佈式環境下的Raft Leader選舉。
獲取Raft算法的實現代碼,請關注公衆號,後臺回覆“ Raft ”獲取源碼。