Raft論文學習筆記


先附上論文鏈接  https://pdos.csail.mit.edu/6.824/papers/raft-extended.pdf

最近在自學MIT的6.824分布式課程,找到兩個比較好的github:MIT課程《Distributed Systems 》學習和翻譯 和 https://github.com/chaozh/MIT-6.824-2017

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日志條目的流動都是雙向的,導致機制比較復雜。

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。

三、日志復制

  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不能提交一個之前任期內的日志條目,否則可能會出現下述情況

 

 

 

  1. 在階段a,term為2,S1是Leader,且S1寫入日志(term, index)為(2, 2),並且日志被同步寫入了S2;
  2. 在階段b,S1離線,觸發一次新的選主,此時S5被選為新的Leader,此時系統term為3,且寫入了日志(term, index)為(3, 2);
  3. S5尚未將日志推送到Followers變離線了,進而觸發了一次新的選主,而之前離線的S1經過重新上線后被選中變成Leader,此時系統term為4,此時S1會將自己的日志同步到Followers,按照上圖就是將日志(2, 2)同步到了S3,而此時由於該日志已經被同步到了多數節點(S1, S2, S3),因此,此時日志(2,2)可以被commit了(即更新到狀態機);
  4. 在階段d,S1又很不幸地下線了,系統觸發一次選主,而S5有可能被選為新的Leader(這是因為S5可以滿足作為主的一切條件:1. term = 5 > 4,2. 最新的日志為(3,2),比大多數節點(如S2/S3/S4的日志都新),然后S5會將自己的日志更新到Followers,於是S2、S3中已經被提交的日志(2,2)被截斷了,這是致命性的錯誤,因為一致性協議中不允許出現已經應用到狀態機中的日志被截斷。

為了避免這種錯誤,Raft要求只有Leader當前term里的日志可以被提交。當然,由於日志匹配特性,之前的日志條目也會被提交。這樣的話由於term被更新,就不會出現4里面說的S5會被選為leader的情況了。

 

參考鏈接:https://zhuanlan.zhihu.com/p/27207160


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM