Raft相對Paxos來說,簡單很多,且易于實施。另外在選舉新Leader方面,Raft優勢較Paxos更加快,筆者在使用ZK過程中,Leader掛掉,需要特別多輪才能選舉出新的Leader
角色
- leader
- flower
- candidate(競選者)
基礎概念
Terms
在分布式系統中,比較棘手的問題就是時間問題,使用物理時間需要確保每臺機器時區完全同步,Terms是Raft為了解決分布式系統中時間同步誕生的,可以將其理解為邏輯時間,它可以幫助server檢測過期信息比如過期的leader。Raft將時間劃分為任意長度的term,用連續整數編號。在收到其他Server發來的請求時,如果發現其他Terms較大,則會更新當前機器Term編號。
Leader選舉
Raft使用心跳機制來觸發leader選舉。當server啟動的時候是處于follower狀態,當它可以收到來自leader或者candidate的有效RPC請求時就會保持follower的狀態。Leader發送周期性的心跳(不含日志的AppendEntries RPC)給所有的follower來確保自己的權威。如果一個follower一段時間(稱為election timeout)沒有收到消息,它就會假定leader失效并開始新的選舉。
為了開始新一輪選舉,follower會提高自己當前的term并轉為candidate狀態。它會先給自己投一票然后并行向集群中的其他server發出RequestVote RPC,candidate會保持這個狀態,直到下面三種事情之一發生:
- (a) 贏得選舉。當candidate收到了集群中相同term的多數節點的贊成票時就會選舉成功,每一個server在給定的term內至多只能投票給一個candidate,先到先得。收到多數節點的選票可以確保在一個term內至多只能有一個leader選出。一旦一個candidate贏得選舉,它就會成為leader。它之后會發送心跳消息來建立自己的權威,并阻止新的選舉。
- (b) 另一個server被確定為leader。在等待投票的過程中,candidate可能收到來自其他server的AppendEntries RPC,聲明它才是leader。如果RPC中的term大于等于candidate的current term,candidate就會認為這個leader是合法的并轉為follower狀態。如果RPC中的term比自己當前的小,將會拒絕這個請求并保持candidate狀態。
- (c) 沒有獲勝者產生,等待選舉超時。candidate沒有選舉成功或者失敗,如果許多follower同時變成candidate,選票就會被瓜分,形不成多數派。這種情況發生時,candidate將會超時并觸發新一輪的選舉,提高term并發送新的RequestVote RPC。然而如果不采取其他措施的話,選票將可能會被再次瓜分。
為了解決再次被瓜分的問題
Raft使用隨機選舉超時來確保選票被瓜分的情況很少出現而且出現了也可以被很快解決。election timeout的值會在一個固定區間內隨機的選取(比如150-300ms)。這使得在大部分情況下僅有一個server會超時,它將會在其他節點超時前贏得選舉并發送心跳。candidate在發起選
日志備份
以下幾個點值得重點關注
- 所有客戶端請求全部由Leader處理,其他Flower收到請求也會轉發給Leader處理
- 客戶端提交每一條命令都會被按順序記錄到leader的日志中,每一條命令都包含term編號和順序索引,然后向其他節點并行發送AppendEntries RPC用以復制命令(如果命令丟失會不斷重發,客戶端重復收到只會覆蓋)
- 假如Leader掛了,日志還沒復制完,leader通過強制follower復制自己的日志來解決上述日志不一致的情形,那么沖突的日志將會被重寫。為了讓日志一致,先找到最新的一致的那條日志(如f中索引為3的日志條目),然后把follower之后的日志全部刪除,leader再把自己在那之后的日志一股腦推送給follower,這樣就實現了一致
日志壓縮
隨著日志大小的增長,會占用更多的內存空間,處理起來也會耗費更多的時間,對系統的可用性造成影響,因此必須想辦法壓縮日志大小。Snapshotting是最簡單的壓縮方法,系統的全部狀態會寫入一個snapshot保存起來,然后丟棄截止到snapshot時間點之前的所有日志