先附上論文連接 https://pdos.csail.mit.edu/6.824/papers/raft-extended.pdfgit
最近在自學MIT的6.824分佈式課程,找到兩個比較好的github:MIT課程《Distributed Systems 》學習和翻譯 和 https://github.com/chaozh/MIT-6.824-2017github
6.824的Lab 2 就是實現Raft算法。Raft是一種分佈式一致性算法,提供了和paxos相同的功能和性能,但比paxos要容易理解不少。算法
一:Raft的一些概念安全
爲了提高可理解性,Raft 將一致性算法分解成了幾個部分:、服務器
1)Leader選舉:當以前的Leader宕機的時候,要選出新的Leader併發
2)日誌複製:Leader從客戶端接收日誌而後複製到集羣中的其它節點,而且要使其它節點的日誌保持和本身相同分佈式
3)安全性:若是有任何的服務器節點已經commit一個日誌條目到它的狀態機中,那麼其它服務器節點不能在同一個日誌索引位置commit一個不一樣的指令。性能
Raft將系統中的角色分爲領導者(Leader)、跟隨者(Follower)和候選人(Candidate):學習
Leader:一般狀況下系統中只有一個Leader,其它服務器節點都是Follower。Leader負責接受客戶端的請求並把日誌同步到Follower。Raft 中日誌條目都遵循着從Leader發送給其它節點這一個方向,這也是Raft追求簡單易懂的體現,像Viewstamped Replication和Zookeeper日誌條目的流動都是雙向的,致使機制比較複雜。spa
Follower:接受並持久化Leader同步的日誌,在Leader告之日誌能夠提交以後,提交日誌。
Candidate:Leader選舉過程當中的臨時角色。
這三種角色的轉換以下圖:
Follower只響應來自其餘服務器的請求。若是Follower接收不到消息,那麼它就會變成Candidate併發起一次選舉。得到集羣中大多數選票的Candidate將成爲Leader。Leader在宕機以前一直都會是Leader。
Raft算法將時間分爲一個個的任期(term),每個term的開始都是Leader選舉。在成功選舉Leader以後,Leader會在整個term內管理整個集羣。若是Leader選舉失敗,該term就會由於沒有Leader而結束,在下一個term繼續選Leader。
二:Leader選舉
Raft 使用一種心跳機制來觸發領導人選舉。在初始狀態,服務器節點都是Follower,若是Follower在一段時間(election timeout)內沒有接收到Leader的心跳,則認爲Leader掛了。此時Follower會將term加1,並轉換爲Candidate狀態。而後Follower會向集羣中其它服務器節點發送RequestVote消息請求其它節點投票給本身。一個節點收到RequestVote 消息後經過比較兩份日誌中最後一條日誌條目的索引值和term得出誰的日誌比較新。若是本節點的日誌比較新,則會拒絕掉該投票請求,不然同意。當Candidate獲得大多數節點的同意後,則此Candidate會成爲Leader,並不斷髮送心跳給其它節點,以維持其Leader地位。
這種選舉方法保證了Leader有着最新的日誌,這樣就能保證日誌條目都遵循着從Leader發送給其它節點這一個方向,使Raft更容易理解。
若是選票被瓜分,會致使全部Candidate都沒法獲得大多數節點的同意票,會致使選舉失敗。在下一輪選舉中,一樣也會出現這種選票瓜分的狀況。爲了不出現這種問題,raft將選舉超時時間隨機化,這樣就不會出現多個Candidate同時選舉超時,再同時發起選舉的狀況。這樣在第一個選舉超時的Candidate會有最大的term,發送RequestVote從而成爲Leader。
3、日誌複製
Leader被選舉出來後,就能夠接受客戶端的請求了。客戶端的每一個請求都包含一條被Replicated State Matchine執行的指令。Leader把客戶端發過來的指令做爲一條新的日誌條目加到日誌中區,隨後發起AppendEntries RPC請求將指令發送給其它節點。當日志條目被安全地複製(大多數節點已經將該日誌條目寫入日誌當中)後,則Leader將這個日誌條目應用到它的狀態機中,而後把執行結果返回給客戶端。
那麼Follower 是怎麼接受來自Leader 的AppendEntries 的呢?先說一下一致性檢查的過程。因爲Follower可能落後Leader一些日誌(好比以前掛了後來恢復了),或者比Leader多一些日誌(好比這個結點是上一個term的Leader,有一些日誌還沒Commited就掛了),而raft要求Follower要完整複製Leader的日誌,因須要進行一致性檢查。在發送AppendEntries RPC時,Leader會包含最新日誌的前一個條目的索引和任期號。若是Follower在日誌中找不到包含相同索引號和任期號的條目,那麼它將會拒接接受新的日誌條目。
Leadre針對每一個Follower維護了一個nextIndex,表示下一個要發送給Follower的日誌條目的索引。當一個Leader剛被選舉出時,將nextIndex初始化爲本身最新日誌的index+1。若是AppendEntries 請求被拒絕,Leader會減少nextIndex進行重試,直到在某個位置Leader和Follower的日誌一致,則AppendEntries RPC成功,Follower上衝突的日誌條目會所有刪除並加上Leader的日誌。這時,Follower的日誌就會和Leader保持一致。
以前任期日誌條目的處理
本輪任期的Leader不能提交一個以前任期內的日誌條目,不然可能會出現下述狀況
爲了不這種錯誤,Raft要求只有Leader當前term裏的日誌能夠被提交。固然,因爲日誌匹配特性,以前的日誌條目也會被提交。這樣的話因爲term被更新,就不會出現4裏面說的S5會被選爲leader的狀況了。