RAFT算法詳解


一、Raft算法概述

1、三種角色

  Raft是一個用於管理日志一致性的協議。它將分布式一致性分解為多個子問題:Leader選舉(Leader election)、日志復制(Log replication)、安全性(Safety)、日志壓縮(Log compaction)等。同時,Raft算法使用了更強的假設來減少了需要考慮的狀態,使之變的易於理解和實現。Raft將系統中的角色分為領導者(Leader)、跟從者(Follower)和候選者(Candidate):

  • Leader:接受客戶端請求,並向Follower同步請求日志,當日志同步到大多數節點上后告訴Follower提交日志。

  • Follower:接受並持久化Leader同步的日志,在Leader告之日志可以提交之后,提交日志。

  • Candidate:Leader選舉過程中的臨時角色。
    在這里插入圖片描述

  Raft要求系統在任意時刻最多只有一個Leader,正常工作期間只有Leader和Followers。Raft算法將時間分為一個個的任期(term),每一個term的開始都是Leader選舉。在成功選舉Leader之后,Leader會在整個term內管理整個集群。如果Leader選舉失敗,該term就會因為沒有Leader而結束。

2、Term

  Raft 算法將時間划分成為任意不同長度的任期(term)。任期用連續的數字進行表示。每一個任期的開始都是一次選舉(election),一個或多個候選人會試圖成為領導人。如果一個候選人贏得了選舉,它就會在該任期的剩余時間擔任領導人。在某些情況下,選票會被瓜分,有可能沒有選出領導人,那么,將會開始另一個任期,並且立刻開始下一次選舉。Raft 算法保證在給定的一個任期最多只有一個領導人。

3、RPC

  Raft 算法中服務器節點之間通信使用遠程過程調用(RPC),並且基本的一致性算法只需要兩種類型的 RPC,為了在服務器之間傳輸快照增加了第三種 RPC。

【RPC有三種】:

  • RequestVote RPC:候選人在選舉期間發起。

  • AppendEntries RPC:領導人發起的一種心跳機制,復制日志也在該命令中完成。

  • InstallSnapshot RPC: 領導者使用該RPC來發送快照給太落后的追隨者。

二、Leader選舉

1、Leader選舉的過程

  Raft 使用心跳(heartbeat)觸發Leader選舉。當服務器啟動時,初始化為Follower。Leader向所有Followers周期性發送heartbeat。如果Follower在選舉超時時間內沒有收到Leader的heartbeat,就會等待一段隨機的時間后發起一次Leader選舉。

  每一個follower都有一個時鍾,是一個隨機的值,表示的是follower等待成為leader的時間,誰的時鍾先跑完,則發起leader選舉。

  Follower將其當前term加一然后轉換為Candidate。它首先給自己投票並且給集群中的其他服務器發送 RequestVote RPC。結果有以下三種情況:

  • 贏得了多數的選票,成功選舉為Leader;

  • 收到了Leader的消息,表示有其它服務器已經搶先當選了Leader;

  • 沒有服務器贏得多數的選票,Leader選舉失敗,等待選舉時間超時后發起下一次選舉。
    在這里插入圖片描述

2、Leader選舉的限制

  在Raft協議中,所有的日志條目都只會從Leader節點往Follower節點寫入,且Leader節點上的日志只會增加,絕對不會刪除或者覆蓋。

  這意味着Leader節點必須包含所有已經提交的日志,即能被選舉為Leader的節點一定需要包含所有的已經提交的日志。因為日志只會從Leader向Follower傳輸,所以如果被選舉出的Leader缺少已經Commit的日志,那么這些已經提交的日志就會丟失,顯然這是不符合要求的。

  這就是Leader選舉的限制:能被選舉成為Leader的節點,一定包含了所有已經提交的日志條目。

三、日志復制(保證數據一致性)

1、日志復制的過程

  Leader選出后,就開始接收客戶端的請求。Leader把請求作為日志條目(Log entries)加入到它的日志中,然后並行的向其他服務器發起 AppendEntries RPC復制日志條目。當這條日志被復制到大多數服務器上,Leader將這條日志應用到它的狀態機並向客戶端返回執行結果。

  • 客戶端的每一個請求都包含被復制狀態機執行的指令。

  • leader把這個指令作為一條新的日志條目添加到日志中,然后並行發起 RPC 給其他的服務器,讓他們復制這條信息。

  • 假如這條日志被安全的復制,領導人就應用這條日志到自己的狀態機中,並返回給客戶端。

  • 如果 follower 宕機或者運行緩慢或者丟包,leader會不斷的重試,直到所有的 follower 最終都復制了所有的日志條目。

在這里插入圖片描述
  簡而言之,leader選舉的過程是:1、增加term號;2、給自己投票;3、重置選舉超時計時器;4、發送請求投票的RPC給其它節點。

2、日志的組成

  日志由有序編號(log index)的日志條目組成。每個日志條目包含它被創建時的任期號(term)和用於狀態機執行的命令。如果一個日志條目被復制到大多數服務器上,就被認為可以提交(commit)了。
在這里插入圖片描述

上圖顯示,共有 8 條日志,提交了 7 條。提交的日志都將通過狀態機持久化到磁盤中,防止宕機。

3、日志的一致性

在這里插入圖片描述

(1)日志復制的兩條保證

  • 如果不同日志中的兩個條目有着相同的索引和任期號,則它們所存儲的命令是相同的(原因:leader 最多在一個任期里的一個日志索引位置創建一條日志條目,日志條目在日志的位置從來不會改變)。

  • 如果不同日志中的兩個條目有着相同的索引和任期號,則它們之前的所有條目都是完全一樣的(原因:每次 RPC 發送附加日志時,leader 會把這條日志條目的前面的日志的下標和任期號一起發送給 follower,如果 follower 發現和自己的日志不匹配,那么就拒絕接受這條日志,這個稱之為一致性檢查)。

(2)日志的不正常情況

  一般情況下,Leader和Followers的日志保持一致,因此 AppendEntries 一致性檢查通常不會失敗。然而,Leader崩潰可能會導致日志不一致:舊的Leader可能沒有完全復制完日志中的所有條目。

  下圖闡述了一些Followers可能和新的Leader日志不同的情況。一個Follower可能會丟失掉Leader上的一些條目,也有可能包含一些Leader沒有的條目,也有可能兩者都會發生。丟失的或者多出來的條目可能會持續多個任期。
在這里插入圖片描述

(3)如何保證日志的正常復制

  Leader通過強制Followers復制它的日志來處理日志的不一致,Followers上的不一致的日志會被Leader的日志覆蓋。Leader為了使Followers的日志同自己的一致,Leader需要找到Followers同它的日志一致的地方,然后覆蓋Followers在該位置之后的條目。

  具體的操作是:Leader會從后往前試,每次AppendEntries失敗后嘗試前一個日志條目,直到成功找到每個Follower的日志一致位置點(基於上述的兩條保證),然后向后逐條覆蓋Followers在該位置之后的條目。

  總結一下就是:當 leader 和 follower 日志沖突的時候,leader 將校驗 follower 最后一條日志是否和 leader 匹配,如果不匹配,將遞減查詢,直到匹配,匹配后,刪除沖突的日志。這樣就實現了主從日志的一致性。

四、安全性

  Raft增加了如下兩條限制以保證安全性:

  • 擁有最新的已提交的log entry的Follower才有資格成為leader。

  • Leader只能推進commit index來提交當前term的已經復制到大多數服務器上的日志,舊term日志的提交要等到提交當前term的日志來間接提交(log index 小於 commit index的日志被間接提交)。
    在這里插入圖片描述

五、日志壓縮

  在實際的系統中,不能讓日志無限增長,否則系統重啟時需要花很長的時間進行回放,從而影響可用性。Raft采用對整個系統進行snapshot來解決,snapshot之前的日志都可以丟棄(以前的數據已經落盤了)。

  每個副本獨立的對自己的系統狀態進行snapshot,並且只能對已經提交的日志記錄進行snapshot。

在這里插入圖片描述

【Snapshot中包含以下內容】:

  • 日志元數據,最后一條已提交的 log entry的 log index和term。這兩個值在snapshot之后的第一條log entry的AppendEntries RPC的完整性檢查的時候會被用上。

  • 系統當前狀態。

  當Leader要發給某個日志落后太多的Follower的log entry被丟棄,Leader會將snapshot發給Follower。或者當新加進一台機器時,也會發送snapshot給它。發送snapshot使用InstalledSnapshot RPC。

  做snapshot既不要做的太頻繁,否則消耗磁盤帶寬, 也不要做的太不頻繁,否則一旦節點重啟需要回放大量日志,影響可用性。推薦當日志達到某個固定的大小做一次snapshot。

  做一次snapshot可能耗時過長,會影響正常日志同步。可以通過使用copy-on-write技術避免snapshot過程影響正常日志同步。

六、成員變更

1、常規處理成員變更存在的問題

  我們先將成員變更請求當成普通的寫請求,由領導者得到多數節點響應后,每個節點提交成員變更日志,將從舊成員配置(Cold)切換到新成員配置(Cnew)。但每個節點提交成員變更日志的時刻可能不同,這將造成各個服務器切換配置的時刻也不同,這就有可能選出兩個領導者,破壞安全性。

  考慮以下這種情況:集群配額從 3 台機器變成了 5 台,可能存在這樣的一個時間點,兩個不同的領導者在同一個任期里都可以被選舉成功(雙主問題),一個是通過舊的配置,一個通過新的配置。

  簡而言之,成員變更存在的問題是增加或者減少的成員太多了,導致舊成員組和新成員組沒有交集,因此出現了雙主。
在這里插入圖片描述

2、解決方案之一階段成員變更

  Raft解決方法是每次成員變更只允許增加或刪除一個成員(如果要變更多個成員,連續變更多次)。
在這里插入圖片描述

七、關於Raft的一些面試題

1、Raft分為哪幾個部分?

  主要是分為leader選舉、日志復制、日志壓縮、成員變更等。

2、Raft中任何節點都可以發起選舉嗎?

  Raft發起選舉的情況有如下幾種:

  • 剛啟動時,所有節點都是follower,這個時候發起選舉,選出一個leader;

  • 當leader掛掉后,時鍾最先跑完的follower發起重新選舉操作,選出一個新的leader。

  • 成員變更的時候會發起選舉操作。

3、Raft中選舉中給候選人投票的前提?

  Raft確保新當選的Leader包含所有已提交(集群中大多數成員中已提交)的日志條目。這個保證是在RequestVoteRPC階段做的,candidate在發送RequestVoteRPC時,會帶上自己的last log entry的term_id和index,follower在接收到RequestVoteRPC消息時,如果發現自己的日志比RPC中的更新,就拒絕投票。日志比較的原則是,如果本地的最后一條log entry的term id更大,則更新,如果term id一樣大,則日志更多的更大(index更大)。

4、Raft網絡分區下的數據一致性怎么解決?

  發生了網絡分區或者網絡通信故障,使得Leader不能訪問大多數Follwer了,那么Leader只能正常更新它能訪問的那些Follower,而大多數的Follower因為沒有了Leader,他們重新選出一個Leader,然后這個 Leader來接受客戶端的請求,如果客戶端要求其添加新的日志,這個新的Leader會通知大多數Follower。如果這時網絡故障修復 了,那么原先的Leader就變成Follower,在失聯階段這個老Leader的任何更新都不能算commit,都回滾,接受新的Leader的新的更新(遞減查詢匹配日志)。
在這里插入圖片描述

5、Raft數據一致性如何實現?

  主要是通過日志復制實現數據一致性,leader將請求指令作為一條新的日志條目添加到日志中,然后發起RPC 給所有的follower,進行日志復制,進而同步數據。

6、Raft的日志有什么特點?

  日志由有序編號(log index)的日志條目組成,每個日志條目包含它被創建時的任期號(term)和用於狀態機執行的命令。

7、Raft和Paxos的區別和優缺點?

  • Raft的leader有限制,擁有最新日志的節點才能成為leader,multi-paxos中對成為Leader的限制比較低,任何節點都可以成為leader。

  • Raft中Leader在每一個任期都有Term號。

8、Raft prevote機制?

在這里插入圖片描述
  Prevote(預投票)是一個類似於兩階段提交的協議,第一階段先征求其他節點是否同意選舉,如果同意選舉則發起真正的選舉操作,否則降為Follower角色。這樣就避免了網絡分區節點重新加入集群,觸發不必要的選舉操作。

9、Raft里面怎么保證數據被commit,leader宕機了會怎樣,之前的沒提交的數據會怎樣?

  leader會通過RPC向follower發出日志復制,等待所有的follower復制完成,這個過程是阻塞的。

  老的leader里面沒提交的數據會回滾,然后同步新leader的數據。

10、Raft日志壓縮是怎么實現的?增加或刪除節點呢??

  在實際的系統中,不能讓日志無限增長,否則系統重啟時需要花很長的時間進行回放,從而影響可用性。Raft采用對整個系統進行snapshot來解決,snapshot之前的日志都可以丟棄(以前的數據已經落盤了)。

  snapshot里面主要記錄的是日志元數據,即最后一條已提交的 log entry的 log index和term。

11、Raft里面的lease機制是什么,有什么作用?

  租約機制確保了一個時刻最多只有一個leader,避免只使用心跳機制產生雙主的問題。中心思想是每次租約時長內只有一個節點獲得租約、到期后必須重新頒發租約。
在這里插入圖片描述

12、Raft協議的leader選舉,正常情況下,網絡抖動造成follower發起leader選舉,且該follower的Term比現有leader高,集群中所有結點的日志信息當前一致,這種情況下會選舉成功嗎?

  參考網絡分區的情況。

參考:https://www.jianshu.com/p/b28e73eefa88


免責聲明!

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



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