Raft協議是分佈式領域解決一致性的又一著名協議,主要包含Leader選舉、日誌複製兩個部分。服務器
舒適提示: 本文根據raft官方給出的raft動畫進行學習,其動畫展現地址:thesecretlivesofdata.com/raft/網絡
一、Leader選舉
1.1 一輪投票中,只有一個節點發起投票的狀況
Raft協議中節點有3種狀態(角色):
- Follower 跟隨者。
- Candidate 候選者。
- Leader 領導者(Leader),一般咱們所說的的主節點。
首先3個節點初始狀態爲 Follower,每一個節點會有一個超時時間(計時器),其時間設置爲150ms~300ms之間的隨機值。當計時器到期後,節點狀態從 Follower 變成 Candidate,以下圖所示: 分佈式
一般狀況下,三個節點中會有一個節點的計時器率先到期,節點狀態變爲 Candidate ,候選者狀態下的節點會發起選舉投票。咱們先來考慮只有一個節點變爲Candidate時是如何進行選主的。
當節點狀態爲Candidate,將發起一輪投票,因爲是第一輪投票,設置本輪投票輪次爲1,並首先爲本身投上一票,正如上圖所示的NodeA節點,Team爲1,Vote Count爲1. 源碼分析
當一個節點的定時器超時後,首先爲本身投上一票,而後向該組內其餘的節點發起投票(用拉票更加合適),發送投票請求。
當集羣內的節點收到投票請求外,若是本輪未進行過投票,則贊同,不然反對,而後將結果返回,並重置計時器。
當節點A收到的贊同票大於一半時,則升級爲該集羣的 Leader,而後定時向集羣內的其餘節點發送心跳,以便肯定本身的領導地位,正以下圖所示。
Node A,集羣中的 Leader正在向其餘節點發送心跳包。
節點在收到 Leader 的心跳包後,返回響應結果,並重置自身的計時器,若是 Flower 狀態的節點在計時時間超時內沒有收到Leader 的心跳包,就會從 Flower 節點變成 Candidate,該節點就會發起下一輪投票。
例如NodeA節點宕機,中止向它的從發送心跳,咱們來看一下集羣如何從新選主。 學習
若是主節點宕機,則中止向集羣內的節點發送心跳包。隨着計時器的到期,節點B的先於節點C變成 Candidate,則節點B向集羣內的其餘節點發起投票,以下圖所示。
節點B,首先將投票輪次設置爲2,而後首先爲本身投上一篇,而後向其餘節點發起投票請求。
節點C收到請求,因爲其投票輪次大於本身的投票輪次,並該輪次並未投票,投出同意票並返回結果,而後重置計時器。節點B將瓜熟蒂落的成爲新的Leader並定時發送心跳包。
3個節點的選主就介紹到這裏了,也許有網友會說,雖然各個節點的計時器是隨機的,但也有可能同一時間,或一個節點在未收到另外一個節點發起的投票請求以前變成 Candidate,即在一輪投票過程當中,有大於1個的節點狀態都是 Candidate,那該如何選主呢?動畫
下面以4個節點的集羣爲例,來闡述上述這種狀況狀況下,如何進行選主。3d
1.2 一輪投票中,超過一個節點發起投票的狀況
首先同時有兩個節點進入Candidate狀態,並開始新的一輪投票,當前投票編號爲4,首先先爲本身投上一票,而後向集羣中的其餘節點發起投票,以下圖所示: 日誌
而後各個節點收到投票請求,以下所示,進行投票:
首先節點C、D在收到D、C節點的投票請求時,都會返回不一樣意,由於在本輪投票中,已經各自爲本身投了一票,按照上圖,節點A贊成C節點、節點B贊成D節點,那此時C、D都只獲的兩票,固然若是A,B都認爲C或D成爲主節點,則選擇就能夠結束了,上圖顯示,C、D都只獲的2票,未超過半數,沒法成爲主節點,那接下來會發生什麼呢?請看下圖:
此時A,B,C,D的定時器各自在倒計時,當節點成爲Candidate時,或自身狀態自己是Candidate而且定時器觸發後,發起一輪新的投票,圖中是節點B、節點D同時發起了新的一輪投票。
投票結果以下:節點A,節點C贊成節點B成爲leader,但因爲BD都發起了第5輪投票,最終的投票輪次更新爲6,如圖所示:
關於Raft協議的選主就介紹到這裏了,接下來咱們來思考一下,若是本身實現 Raf t協議,至少要考慮哪些問題,爲下一篇源碼閱讀Dleger(RocketMQ多副本)模塊提供一些思路。
1.3 思考如何實現Raft選主
- 節點狀態 須要引入3中節點狀態:Follower(跟隨者)、Candidate(候選者),投票的觸發點,Leader(主節點)。
- 進入投票狀態的計時器 Follower、Candidate 兩個狀態時,須要維護一個計時器,每次定時時間從150ms-300ms之間進行隨機,即每一個節點的每次的計時過時不同,Follower狀態時,計時器到點後,觸發一輪投票。節點在收到投票請求、Leader 的心跳請求並做出響應後須要重置定時器。
- 投票輪次Team Candidate 狀態的節點,每發起一輪投票,Term 加一;Term的存儲。
- 投票機制 每一輪一個節點只能爲一個節點投同意票,例如節點A中維護的輪次爲3,而且已經爲節點B投了同意票,若是收到其餘節點,投票輪次爲3,則會投反對票,若是收到輪次爲4的節點,是又能夠投同意票的。
- 成爲Leader的條件 必須獲得集羣中節點的大多數,即超過半數,例如若是集羣中有3個節點,則必須獲得兩票,若是其中一臺服務器宕機,剩下的兩個節點,還能進行選主嗎?答案是能夠的,由於能夠獲得2票,超過初始集羣中3的一半,因此一般集羣中的機器各位儘可能爲計數,由於4臺的可用性與3臺的同樣。
舒適提示:上述結論只是個人一些思考,咱們能夠帶着上述思考,進入到Dleger的學習中,下一篇將從源碼分析的角度來學習大神是如何實現Raft協議的Leader選主的,讓咱們一塊兒期待吧。cdn
二、日誌複製
完成集羣內的選主工做後,客戶端向主節點發送請求,由主節點負責數據的複製,使集羣內的數據保持一致性,初始狀態以下圖所示: 中間件
客戶端向主節點發起請求,例如set 5,將數據更新爲5,以下圖所示:
主節點收到客戶端請求後,將數據追加到Leader的日誌中(但未提交),而後在下一個心跳包中將日誌轉發到集羣內從節點,以下圖所示:
從節點收到Leader的日誌後,追加到從節點的日誌文件中,並返回確認ACK。Leader收到從節點的確認信息後,向客戶端發送確認信息。
上述的日誌複製比較簡單,是因爲只考慮正常的狀況,若是中間發生異常,該如何保證數據一致性呢?
- 若是 Leader 節點向從節點廣播日誌時,其中某個從節點發送故障宕機,該如何處理呢?
- 日誌在什麼環節進行提交呢?Leader節點在收到客戶端的數據變動請求後,首先追加到主節點的日誌文件中,而後廣播到從節點,從節點收到日誌信息,是提交日誌後返回ACK,仍是何時提交呢?
- 日誌如何保證惟一。
- 如何處理網絡出現分區。
我相信讀者朋友確定還有更多的疑問,本文不打算來回答上述疑問,而是帶着這些問題進入到RocketMQ多副本的學習中,經過源碼分析RocketMQ DLedger的實現後,再來從新總結raft協議。
親愛的讀者們,讀到這裏了,煩請點個贊,謝謝,下一篇將重點分析RocketMQ Dledger 多副本模塊如何實現 raft 協議的選主。
做者簡介:《RocketMQ技術內幕》做者,RocketMQ 社區佈道師,維護公衆號:中間件興趣圈,可掃描以下二維碼與做者進行互動。