經典分佈式論文閱讀:Raft

本文是Raft算法論文的學習筆記,Raft是一個用於管理多副本日誌的共識算法。共識算法運行集羣即便在少數節點崩潰的狀況下,讓集羣中的節點一致工做。Raft算法有如下特性:git

  • 強領導:相對於其餘一致算法,Raft使用強領導;
  • 領導選舉:Raft使用隨機時間來選舉領導;
  • 成員變動:使用聯合一致運行配置變動時存在重疊狀態。

多副本狀態機

共識算法涉及到了多副本狀態機的概念,多副本狀態機就是一組服務器作相同的狀態副本,即便在一些服務器下線以後仍是能夠繼續操做。多副本狀態機一般使用多副本日誌實現,而維護多副本日誌就是共識算法的任務。github

共識算法有如下特性:算法

  • 在非拜占庭條件下保證安全性;
  • 只要多數服務器可操做可以相互通訊,共識算法就是可用的;
  • 不依賴時鐘;
  • 只要大部分節點相應了,那麼提交的命令就認爲已經完成。

爲了便於理解而設計

Paxos首次解決了一致性協議問題,可是問題在於:安全

  • Paxos很難理解
  • Paxos並無給工程實現提供很好的基礎

Raft主要使用了兩個思路提升可理解性:服務器

  1. 將問題分爲多個子問題獨立解決;
  2. 簡化須要考慮的狀態數量,提升系統一致性,排除不肯定性。

Raft共識算法

Raft完整算法以下圖所示:性能

Raft算法能夠分爲三個子問題進行討論:學習

  • 領導選舉:當存領導故障以後,如何選舉出新的領導;
  • 日誌備份:領導從客戶端接收日誌條目備份到集羣上;
  • 安全性:Raft的安全性保證以下
    • 選舉安全性:一個term中最多選舉出一個領導;
    • 領導只能追加:領導永遠不會刪除日誌中的條目,只會追加新的條目;
    • 日誌匹配:若是兩個日誌中的條目具備相同的indexterm,那麼到這條爲止的日誌條目都是相同的;
    • 領導完整性:若是一個日誌條目被提交到了一個term裏,那這個日誌條目會出如今全部高term領導的日誌中;
    • 狀態機安全性:若是一個服務器將一個日誌條目應用到了狀態機中,不存在其餘服務器應用了相同index的其餘不一樣命令。

Raft基礎

任何服務器會處於三種狀態的一種:領導下屬候選,狀態的切換狀態機以下所示:設計

Raft將時間劃分爲任意長度的term,每一個term從一次選舉開始,贏得選舉的節點做爲當前term的領導。當選舉失敗或者領導節點崩潰,那麼須要開始一個新的term。3d

領導選舉

領導週期性向下屬發送AppendEntries RPC來保持「心跳」,若是沒有新增的日誌就發送空內容,當下屬在一段時間(選舉超時)內沒有收到任何消息時,那麼進入候選狀態啓動選舉。若是候選人獲得多數服務器的投票,服務器轉換爲領導狀態,向其餘服務器發送AppendEntries RPC。日誌

爲了不同時產生多個候選節點,每一個服務器的選舉超時時間都須要從一個區間中隨機選擇。在集羣沒有領導的時候,候選節點須要等待一段選舉超時時間後再開始下一輪選舉。

日誌備份

領導節點從客戶端接收條目後追加到本身的日誌中,而後經過AppendEntries RPC將日誌發送給其餘節點創建副本。當領導得知副本到達多數節點後,便可提交日誌條目。Raft保證已經提交的條目是持久的,而且最終會被所有可用的狀態機執行。當日志條目備份到了多數的服務器上,那麼便可提交:

Raft知足如下特徵來保證日誌匹配性

  • 若是不一樣日誌中兩個條目有相同的termindex,那麼他們保存同一條命令;
  • 若是不一樣日誌中兩個條目有相同的termindex,那麼他們以前的全部日誌都是相同的。

當領導節點開始管理集羣的時候,各個服務器上的日誌可能以下:

有些下屬丟失了日誌條目(a-b),有些下屬包含了額外可是還沒有提交的條目(c-d),或者兩種狀況都有(e-f)。其中f是由於它是term2和3的領導,可是都沒有提交成功任何條目。不管如何,下屬服務器上的日誌中衝突的條目會被領導的日誌所覆蓋。

領導服務器維護了nextIndex來保存須要發送給下屬的下一個條目,當領導初始化的時候,將nextIndex初始化爲服務器的最後一個條目。若是下屬服務器的日誌和領導服務器日誌不同,那麼AppendEntries RPC會失敗,這個時候領導將nextIndex減一以後重試。對於那些由於故障致使日誌丟失或者落後的服務器,AppendEntries的一致性檢查可以幫助恢復日誌。

安全性

選舉限制

領導完整性要求任意一個term的領導必須包含以前term提交的全部日誌條目。爲了保證這個特徵,Raft要求候選服務器必須包含全部的提交日誌才能得到選舉。所以,RequestVote RPC包含了候選服務器的日誌,若是投票服務器的日誌更新,那麼拒絕投票。

提交先前term的條目

Raft永遠不會提交以前term的條目。以下圖,假設領導節點S1將2備份到S2以後掉線(a),而後S5成爲領導收到3後掉線(b),而後S1從新成爲領導後繼續備份2到大多數節點後提交2,可是再次下線(c),可是若是S5從新成爲領導以後會覆蓋2(d),可是若是4被提交的話,2就不會被覆蓋,由於S5不可能成爲領導。

Raft領導只會提交當前term以內的條目;這樣一來,當一個條目提交以後,可以確保以前全部的條目都被提交,知足日誌匹配性。

安全性討論

咱們可使用反證法證實領導完整性成立。假設在term提交的一條日誌條目沒有保存到將來的領導服務器日誌中。那麼令不包含該條條目的最小term爲U(U>T)。

  1. 那麼在選舉的時候,該條目必定不在領導U的日誌中(領導服務器毫不刪除和覆蓋日誌);
  2. 那麼領導T必定在多數服務器熵備份了該日誌,同時領導U收到了多數投票;
  3. 那麼至少有一個投票給領導U服務器收到了提交的條目;
  4. 所以在投票給U的時候必然已經保存了該條目;
  5. 既然投票給了U,那麼領導U的日誌至少和投票者同樣新,那麼不可能不包含該日誌條目,與假設衝突。

領導完整性成立進一步能夠證實狀態機安全性。

下屬和候選服務器崩潰

下屬和候選服務器崩潰以後,RPC請求就會失敗,Raft採用無限次嘗試的方法,當服務器重啓以後隨着RPC處理的進行天然恢復。

時間和可用性

Raft的安全性並不依賴於時間:系統不會由於某些事件發生地更快或者更慢而產生不正確地結果。

可是,Raft對於選舉超時時間仍是有着必定地要求:

broadcastTime ≪ electionTimeout ≪ MTBF

broadcastTime是服務器並行向全部其餘服務器發送RPC須要地時間,MTBF是單個服務器發送故障的平均時間。

集羣成員管理變動

爲了保障安全性,配置更改須要使用兩階段的形式。在Raft中應用配置更改的時候,首先進入一個稱爲聯合共識的過渡狀態,在這個狀態中

  • 日誌條目在兩種配置的服務器上均保留副本;
  • 兩個配置的服務器均可以稱爲領導;
  • 一致須要分別獲得兩種配置服務器的多數認同。

集羣配置被保存在一個特殊的日誌條目中,一旦一個服務器將新配置條目加入日誌,它就會在將來全部操做中使用新的配置。

配置變動過程以下:

  1. 提交併應用過渡狀態C_{old,new}(保存在新集羣中的多數和舊集羣中的多數),這時就能夠安全地嘗試提交C_{new}了;
  2. 提交併應用新的配置C_{new}(保存在新集羣的多數)。

在變動配置的時候會存在如下三個問題:

  1. 新的服務器最初沒有任何日誌條目。若是直接參與共識,須要耗費大量時間。所以,在添加新服務器以前,能夠將它做爲無投票權節點直接從領導節點獲取日誌條目。
  2. 領導節點再也不是新配置下的成員。這種狀況下,在提交C_{new}的時候,領導節點就不須要計入本身的投票,C_{new}提交以後,領導節點隨即下線。
  3. 已經移除的服務器可能會干擾現有的集羣C_new提交以後,舊節點再也不會接收到心跳,它們會超時發起選舉干擾新節點,可讓新節點無視收到心跳包必定時間內的RequestVote來解決。

日誌壓縮

根據Raft算法,重啓的節點能夠重放日誌進行恢復,可是若是日誌很長會給恢復過程帶來壓力。一個直觀的方法就是經過快照來壓縮日誌。

每一個節點獨立維護本身的快照,只將已經提交的日誌保存到快照中。節點須要保存快照包含的最後一個termindex用於處理AppendEntries是檢查一致性。對於領導節點,須要發送InstallSnapshot遠程調用將本身的快照給那些落後的節點幫助其遇上最新狀態。

快照機制存在兩個性能問題:

  • 建立快照的時機:太快消耗存儲,太慢拖慢恢復,簡單的策略能夠在達到必定大小後再寫入;
  • 寫入快照會花費大量的時間:針對快照更新採用寫時複製,避免了沒必要要的複製。

客戶端交互

客戶端須要找到正確的領導節點,客戶端會隨機鏈接一個節點,隨機節點會告知客戶端領導節點的信息。

若是領導節點在提交某日誌條目後沒來得及通知客戶端時崩潰,那麼客戶端聯繫新領導節點重試的時候重複執行指令,可讓客戶端給每個指令設置一個序列號解決。

因爲只讀操做不須要提交日誌條目,所以可能會從舊的領導節點讀取舊數據,Raft使用了兩個額外要求來解決:

  • 首先領導節點必須擁有最新的提交條目;
  • 領導節點在響應只讀操做的時候須要確認本身是否被遺棄。

參考文獻

  1. Ongaro, Diego, and John K. Ousterhout. "In search of an understandable consensus algorithm." USENIX Annual Technical Conference. 2014.
相關文章
相關標籤/搜索