1. 程式人生 > 程式設計 >經典分散式論文閱讀:Raft

經典分散式論文閱讀:Raft

本文是Raft演演算法論文的學習筆記,Raft是一個用於管理多副本日誌的共識演演算法。共識演演算法執行叢集即使在少數節點崩潰的情況下,讓叢集中的節點一致工作。Raft演演算法有以下特性:

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

多副本狀態機

共識演演算法涉及到了多副本狀態機的概念,多副本狀態機就是一組伺服器做相同的狀態副本,即使在一些伺服器下線之後還是可以繼續操作。多副本狀態機通常使用多副本日誌實現,而維護多副本日誌就是共識演演算法的任務。

共識演演算法有以下特性:

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

為了便於理解而設計

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

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

Raft主要使用了兩個思路提高可理解性:

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

Raft共識演演算法

Raft完整演演算法如下圖所示:

Raft演演算法可以分為三個子問題進行討論:

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

Raft基礎

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

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

領導選舉

領導週期性向下屬傳送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.