尋找一種易於理解的一致性演算法(擴充套件版)下

深入淺出區塊鏈發表於2019-03-24

6 叢集成員變化

到目前為止,我們都假設叢集的配置(加入到一致性演算法的伺服器集合)是固定不變的。但是在實踐中,偶爾是會改變叢集的配置的,例如替換那些當機的機器或者改變複製級別。儘管可以通過暫停整個叢集,更新所有配置,然後重啟整個叢集的方式來實現,但是在更改的時候叢集會不可用。另外,如果存在手工操作步驟,那麼就會有操作失誤的風險。為了避免這樣的問題,我們決定自動化配置改變並且將其納入到 Raft 一致性演算法中來。

為了讓配置修改機制能夠安全,那麼在轉換的過程中不能夠存在任何時間點使得兩個領導人同時被選舉成功在同一個任期裡。不幸的是,任何伺服器直接從舊的配置直接轉換到新的配置的方案都是不安全的。一次性自動的轉換所有伺服器是不可能的,所以在轉換期間整個叢集存在劃分成兩個獨立的大多數群體的可能性(見圖 10)。

圖 10

圖 10:直接從一種配置轉到新的配置是十分不安全的,因為各個機器可能在任何的時候進行轉換。在這個例子中,叢集配額從 3 臺機器變成了 5 臺。不幸的是,存在這樣的一個時間點,兩個不同的領導人在同一個任期裡都可以被選舉成功。一個是通過舊的配置,一個通過新的配置。

為了保證安全性,配置更改必須使用兩階段方法。目前有很多種兩階段的實現。例如,有些系統在第一階段停掉舊的配置所以叢集就不能處理客戶端請求;然後在第二階段在啟用新的配置。在 Raft 中,叢集先切換到一個過渡的配置,我們稱之為共同一致;一旦共同一致已經被提交了,那麼系統就切換到新的配置上。共同一致是老配置和新配置的結合:

  • 日誌條目被複制給叢集中新、老配置的所有伺服器。
  • 新、舊配置的伺服器都可以成為領導人。
  • 達成一致(針對選舉和提交)需要分別在兩種配置上獲得大多數的支援。

共同一致允許獨立的伺服器在不影響安全性的前提下,在不同的時間進行配置轉換過程。此外,共同一致可以讓叢集在配置轉換的過程人依然響應客戶端的請求。

叢集配置在複製日誌中以特殊的日誌條目來儲存和通訊;圖 11 展示了配置轉換的過程。當一個領導人接收到一個改變配置從 C-old 到 C-new 的請求,他會為了共同一致儲存配置(圖中的 C-old,new),以前面描述的日誌條目和副本的形式。一旦一個伺服器將新的配置日誌條目增加到它的日誌中,他就會用這個配置來做出未來所有的決定(伺服器總是使用最新的配置,無論他是否已經被提交)。這意味著領導人要使用 C-old,new 的規則來決定日誌條目 C-old,new 什麼時候需要被提交。如果領導人崩潰了,被選出來的新領導人可能是使用 C-old 配置也可能是 C-old,new 配置,這取決於贏得選舉的候選人是否已經接收到了 C-old,new 配置。在任何情況下, C-new 配置在這一時期都不會單方面的做出決定。

一旦 C-old,new 被提交,那麼無論是 C-old 還是 C-new,在沒有經過他人批准的情況下都不可能做出決定,並且領導人完全特性保證了只有擁有 C-old,new 日誌條目的伺服器才有可能被選舉為領導人。這個時候,領導人建立一條關於 C-new 配置的日誌條目並複製給叢集就是安全的了。再者,每個伺服器在見到新的配置的時候就會立即生效。當新的配置在 C-new 的規則下被提交,舊的配置就變得無關緊要,同時不使用新的配置的伺服器就可以被關閉了。如圖 11,C-old 和 C-new 沒有任何機會同時做出單方面的決定;這保證了安全性。

圖 11

圖 11:一個配置切換的時間線。虛線表示已經被建立但是還沒有被提交的條目,實線表示最後被提交的日誌條目。領導人首先建立了 C-old,new 的配置條目在自己的日誌中,並提交到 C-old,new 中(C-old 的大多數和 C-new 的大多數)。然後他建立 C-new 條目並提交到 C-new 中的大多數。這樣就不存在 C-new 和 C-old 可以同時做出決定的時間點。

在關於重新配置還有三個問題需要提出。第一個問題是,新的伺服器可能初始化沒有儲存任何的日誌條目。當這些伺服器以這種狀態加入到叢集中,那麼他們需要一段時間來更新追趕,這時還不能提交新的日誌條目。為了避免這種可用性的間隔時間,Raft 在配置更新的時候使用了一種額外的階段,在這個階段,新的伺服器以沒有投票權身份加入到叢集中來(領導人複製日誌給他們,但是不考慮他們是大多數)。一旦新的伺服器追趕上了叢集中的其他機器,重新配置可以像上面描述的一樣處理。

第二個問題是,叢集的領導人可能不是新配置的一員。在這種情況下,領導人就會在提交了 C-new 日誌之後退位(回到跟隨者狀態)。這意味著有這樣的一段時間,領導人管理著叢集,但是不包括他自己;他複製日誌但是不把他自己算作是大多數之一。當 C-new 被提交時,會發生領導人過渡,因為這時是最早新的配置可以獨立工作的時間點(將總是能夠在 C-new 配置下選出新的領導人)。在此之前,可能只能從 C-old 中選出領導人。

第三個問題是,移除不在 C-new 中的伺服器可能會擾亂叢集。這些伺服器將不會再接收到心跳,所以當選舉超時,他們就會進行新的選舉過程。他們會傳送擁有新的任期號的請求投票 RPCs,這樣會導致當前的領導人回退成跟隨者狀態。新的領導人最終會被選出來,但是被移除的伺服器將會再次超時,然後這個過程會再次重複,導致整體可用性大幅降低。

為了避免這個問題,當伺服器確認當前領導人存在時,伺服器會忽略請求投票 RPCs。特別的,當伺服器在當前最小選舉超時時間內收到一個請求投票 RPC,他不會更新當前的任期號或者投出選票。這不會影響正常的選舉,每個伺服器在開始一次選舉之前,至少等待一個最小選舉超時時間。然而,這有利於避免被移除的伺服器擾亂:如果領導人能夠傳送心跳給叢集,那麼他就不會被更大的任期號廢黜。

7 日誌壓縮

Raft 的日誌在正常操作中不斷的增長,但是在實際的系統中,日誌不能無限制的增長。隨著日誌不斷增長,他會佔用越來越多的空間,花費越來越多的時間來重置。如果沒有一定的機制去清除日誌裡積累的陳舊的資訊,那麼會帶來可用性問題。

快照是最簡單的壓縮方法。在快照系統中,整個系統的狀態都以快照的形式寫入到穩定的持久化儲存中,然後到那個時間點之前的日誌全部丟棄。快照技術被使用在 Chubby 和 ZooKeeper 中,接下來的章節會介紹 Raft 中的快照技術。

增量壓縮的方法,例如日誌清理或者日誌結構合併樹,都是可行的。這些方法每次只對一小部分資料進行操作,這樣就分散了壓縮的負載壓力。首先,他們先選擇一個已經積累的大量已經被刪除或者被覆蓋物件的區域,然後重寫那個區域還活躍的物件,之後釋放那個區域。和簡單操作整個資料集合的快照相比,需要增加複雜的機制來實現。狀態機可以實現 LSM tree 使用和快照相同的介面,但是日誌清除方法就需要修改 Raft 了。

圖 12

圖 12:一個伺服器用新的快照替換了從 1 到 5 的條目,快照值儲存了當前的狀態。快照中包含了最後的索引位置和任期號。

圖 12 展示了 Raft 中快照的基礎思想。每個伺服器獨立的建立快照,只包括已經被提交的日誌。主要的工作包括將狀態機的狀態寫入到快照中。Raft 也包含一些少量的後設資料到快照中:最後被包含索引指的是被快照取代的最後的條目在日誌中的索引值(狀態機最後應用的日誌),最後被包含的任期指的是該條目的任期號。保留這些資料是為了支援快照後緊接著的第一個條目的附加日誌請求時的一致性檢查,因為這個條目需要前一日誌條目的索引值和任期號。為了支援叢集成員更新(第 6 節),快照中也將最後的一次配置作為最後一個條目存下來。一旦伺服器完成一次快照,他就可以刪除最後索引位置之前的所有日誌和快照了。

儘管通常伺服器都是獨立的建立快照,但是領導人必須偶爾的傳送快照給一些落後的跟隨者。這通常發生在當領導人已經丟棄了下一條需要傳送給跟隨者的日誌條目的時候。幸運的是這種情況不是常規操作:一個與領導人保持同步的跟隨者通常都會有這個條目。然而一個執行非常緩慢的跟隨者或者新加入叢集的伺服器(第 6 節)將不會有這個條目。這時讓這個跟隨者更新到最新的狀態的方式就是通過網路把快照傳送給他們。

安裝快照 RPC

由領導人呼叫以將快照的分塊傳送給跟隨者。領導者總是按順序傳送分塊。

引數 解釋
term 領導人的任期號
leaderId 領導人的 Id,以便於跟隨者重定向請求
lastIncludedIndex 快照中包含的最後日誌條目的索引值
lastIncludedTerm 快照中包含的最後日誌條目的任期號
offset 分塊在快照中的位元組偏移量
data[] 原始資料
done 如果這是最後一個分塊則為 true
結果 解釋
term 當前任期號(currentTerm),便於領導人更新自己

接收者實現

  1. 如果term < currentTerm就立即回覆
  2. 如果是第一個分塊(offset 為 0)就建立一個新的快照
  3. 在指定偏移量寫入資料
  4. 如果 done 是 false,則繼續等待更多的資料
  5. 儲存快照檔案,丟棄具有較小索引的任何現有或部分快照
  6. 如果現存的日誌條目與快照中最後包含的日誌條目具有相同的索引值和任期號,則保留其後的日誌條目並進行回覆
  7. 丟棄整個日誌
  8. 使用快照重置狀態機(並載入快照的叢集配置)

圖 13

圖 13:一個關於安裝快照的簡要概述。為了便於傳輸,快照都是被分成分塊的;每個分塊都給了跟隨者生命的跡象,所以跟隨者可以重置選舉超時計時器。

在這種情況下領導人使用一種叫做安裝快照的新的 RPC 來傳送快照給太落後的跟隨者;見圖 13。當跟隨者通過這種 RPC 接收到快照時,他必須自己決定對於已經存在的日誌該如何處理。通常快照會包含沒有在接收者日誌中存在的資訊。在這種情況下,跟隨者丟棄其整個日誌;它全部被快照取代,並且可能包含與快照衝突的未提交條目。如果接收到的快照是自己日誌的前面部分(由於網路重傳或者錯誤),那麼被快照包含的條目將會被全部刪除,但是快照後面的條目仍然有效,必須保留。

這種快照的方式背離了 Raft 的強領導人原則,因為跟隨者可以在不知道領導人情況下建立快照。但是我們認為這種背離是值得的。領導人的存在,是為了解決在達成一致性的時候的衝突,但是在建立快照的時候,一致性已經達成,這時不存在衝突了,所以沒有領導人也是可以的。資料依然是從領導人傳給跟隨者,只是跟隨者可以重新組織他們的資料了。

我們考慮過一種替代的基於領導人的快照方案,即只有領導人建立快照,然後傳送給所有的跟隨者。但是這樣做有兩個缺點。第一,傳送快照會浪費網路頻寬並且延緩了快照處理的時間。每個跟隨者都已經擁有了所有產生快照需要的資訊,而且很顯然,自己從本地的狀態中建立快照比通過網路接收別人發來的要經濟。第二,領導人的實現會更加複雜。例如,領導人需要傳送快照的同時並行的將新的日誌條目傳送給跟隨者,這樣才不會阻塞新的客戶端請求。

還有兩個問題影響了快照的效能。首先,伺服器必須決定什麼時候應該建立快照。如果快照建立的過於頻繁,那麼就會浪費大量的磁碟頻寬和其他資源;如果建立快照頻率太低,他就要承受耗盡儲存容量的風險,同時也增加了從日誌重建的時間。一個簡單的策略就是當日志大小達到一個固定大小的時候就建立一次快照。如果這個閾值設定的顯著大於期望的快照的大小,那麼快照對磁碟壓力的影響就會很小了。

第二個影響效能的問題就是寫入快照需要花費顯著的一段時間,並且我們還不希望影響到正常操作。解決方案是通過寫時複製的技術,這樣新的更新就可以被接收而不影響到快照。例如,具有函式式資料結構的狀態機天然支援這樣的功能。另外,作業系統的寫時複製技術的支援(如 Linux 上的 fork)可以被用來建立完整的狀態機的記憶體快照(我們的實現就是這樣的)。

8 客戶端互動

這一節將介紹客戶端是如何和 Raft 進行互動的,包括客戶端如何發現領導人和 Raft 是如何支援線性化語義的。這些問題對於所有基於一致性的系統都存在,並且 Raft 的解決方案和其他的也差不多。

Raft 中的客戶端傳送所有請求給領導人。當客戶端啟動的時候,他會隨機挑選一個伺服器進行通訊。如果客戶端第一次挑選的伺服器不是領導人,那麼那個伺服器會拒絕客戶端的請求並且提供他最近接收到的領導人的資訊(附加條目請求包含了領導人的網路地址)。如果領導人已經崩潰了,那麼客戶端的請求就會超時;客戶端之後會再次重試隨機挑選伺服器的過程。

我們 Raft 的目標是要實現線性化語義(每一次操作立即執行,只執行一次,在他呼叫和收到回覆之間)。但是,如上述,Raft 是可以執行同一條命令多次的:例如,如果領導人在提交了這條日誌之後,但是在響應客戶端之前崩潰了,那麼客戶端會和新的領導人重試這條指令,導致這條命令就被再次執行了。解決方案就是客戶端對於每一條指令都賦予一個唯一的序列號。然後,狀態機跟蹤每條指令最新的序列號和相應的響應。如果接收到一條指令,它的序列號已經被執行了,那麼就立即返回結果,而不重新執行指令。

只讀的操作可以直接處理而不需要記錄日誌。但是,在不增加任何限制的情況下,這麼做可能會冒著返回髒資料的風險,因為領導人響應客戶端請求時可能已經被新的領導人作廢了,但是他還不知道。線性化的讀操作必須不能返回髒資料,Raft 需要使用兩個額外的措施在不使用日誌的情況下保證這一點。首先,領導人必須有關於被提交日誌的最新資訊。領導人完全特性保證了領導人一定擁有所有已經被提交的日誌條目,但是在他任期開始的時候,他可能不知道那些是已經被提交的。為了知道這些資訊,他需要在他的任期裡提交一條日誌條目。Raft 中通過領導人在任期開始的時候提交一個空白的沒有任何操作的日誌條目到日誌中去來實現。第二,領導人在處理只讀的請求之前必須檢查自己是否已經被廢黜了(他自己的資訊已經變髒瞭如果一個更新的領導人被選舉出來)。Raft 中通過讓領導人在響應只讀請求之前,先和叢集中的大多數節點交換一次心跳資訊來處理這個問題。可選的,領導人可以依賴心跳機制來實現一種租約的機制,但是這種方法依賴時間來保證安全性(假設時間誤差是有界的)。

9 演算法實現和評估

我們已經為 RAMCloud 實現了 Raft 演算法作為儲存配置資訊的複製狀態機的一部分,並且幫助 RAMCloud 協調故障轉移。這個 Raft 實現包含大約 2000 行 C++ 程式碼,其中不包括測試、註釋和空行。這些程式碼是開源的。同時也有大約 25 個其他獨立的第三方的基於這篇論文草稿的開源實現,針對不同的開發場景。同時,很多公司已經部署了基於 Raft 的系統。

這一節會從三個方面來評估 Raft 演算法:可理解性、正確性和效能。

9.1 可理解性

為了和 Paxos 比較 Raft 演算法的可理解能力,我們針對高層次的本科生和研究生,在史丹佛大學的高階作業系統課程和加州大學伯克利分校的分散式計算課程上,進行了一次學習的實驗。我們分別拍了針對 Raft 和 Paxos 的視訊課程,並準備了相應的小測驗。Raft 的視訊講課覆蓋了這篇論文的所有內容除了日誌壓縮;Paxos 講課包含了足夠的資料來建立一個等價的複製狀態機,包括單決策 Paxos,多決策 Paxos,重新配置和一些實際系統需要的效能優化(例如領導人選舉)。小測驗測試一些對演算法的基本理解和解釋一些邊角的示例。每個學生都是看完第一個視訊,回答相應的測試,再看第二個視訊,回答相應的測試。大約有一半的學生先進行 Paxos 部分,然後另一半先進行 Raft 部分,這是為了說明兩者從第一部分的演算法學習中獲得的表現和經驗的差異。我們計算參加人員的每一個小測驗的得分來看參與者是否在 Raft 演算法上更加容易理解。

我們儘可能的使得 Paxos 和 Raft 的比較更加公平。這個實驗偏愛 Paxos 表現在兩個方面:43 個參加者中有 15 個人在之前有一些 Paxos 的經驗,並且 Paxos 的視訊要長 14%。如表格 1 總結的那樣,我們採取了一些措施來減輕這種潛在的偏見。我們所有的材料都可供審查。

關心 緩和偏見採取的手段 可供檢視的材料
相同的講課質量 兩者使用同一個講師。Paxos 使用的是現在很多大學裡經常使用的。Paxos 會長 14%。 視訊
相同的測驗難度 問題以難度分組,在兩個測驗裡成對出現。 小測驗
公平評分 使用評價量規。隨機順序打分,兩個測驗交替進行。 評價量規(rubric)

表 1:考慮到可能會存在的偏見,對於每種情況的解決方法,和相應的材料。

參加者平均在 Raft 的測驗中比 Paxos 高 4.9 分(總分 60,那麼 Raft 的平均得分是 25.7,而 Paxos 是 20.8);圖 14 展示了每個參與者的得分。配置t-檢驗(又稱student‘s t-test)表明,在 95% 的可信度下,真實的 Raft 分數分佈至少比 Paxos 高 2.5 分。

圖 14

圖 14:一個散點圖表示了 43 個學生在 Paxos 和 Raft 的小測驗中的成績。在對角線之上的點表示在 Raft 獲得了更高分數的學生。

我們也建立了一個線性迴歸模型來預測一個新的學生的測驗成績,基於以下三個因素:他們使用的是哪個小測驗,之前對 Paxos 的經驗,和學習演算法的順序。模型預測,對小測驗的選擇會產生 12.5 分的差別。這顯著的高於之前的 4.9 分,因為很多學生在之前都已經有了對於 Paxos 的經驗,這相當明顯的幫助 Paxos,對 Raft 就沒什麼太大影響了。但是奇怪的是,模型預測對於先進行 Paxos 小測驗的人而言,Raft的得分低了6.3分; 雖然我們不知道為什麼,這似乎在統計上是有意義的。

我們同時也在測驗之後調查了參與者,他們認為哪個演算法更加容易實現和解釋;這個的結果在圖 15 上。壓倒性的結果表明 Raft 演算法更加容易實現和解釋(41 人中的 33個)。但是,這種自己報告的結果不如參與者的成績更加可信,並且參與者可能因為我們的 Raft 更加易於理解的假說而產生偏見。

圖 15

圖 15:通過一個 5 分制的問題,參與者(左邊)被問哪個演算法他們覺得在一個高效正確的系統裡更容易實現,右邊被問哪個更容易向學生解釋。

關於 Raft 使用者學習有一個更加詳細的討論。

9.2 正確性

在第 5 節,我們已經制定了正式的規範,和對一致性機制的安全性證明。這個正式規範使用 TLA+ 規範語言使圖 2 中總結的資訊非常清晰。它長約400行,並作為證明的主題。同時對於任何想實現 Raft 的人也是十分有用的。我們通過 TLA 證明系統非常機械的證明了日誌完全特性。然而,這個證明依賴的約束前提還沒有被機械證明(例如,我們還沒有證明規範的型別安全)。而且,我們已經寫了一個非正式的證明關於狀態機安全性是完備的,並且是相當清晰的(大約 3500 個詞)。

9.3 效能

Raft 和其他一致性演算法例如 Paxos 有著差不多的效能。在效能方面,最重要的關注點是,當領導人被選舉成功時,什麼時候複製新的日誌條目。Raft 通過很少數量的訊息包(一輪從領導人到叢集大多數機器的訊息)就達成了這個目的。同時,進一步提升 Raft 的效能也是可行的。例如,很容易通過支援批量操作和管道操作來提高吞吐量和降低延遲。對於其他一致性演算法已經提出過很多效能優化方案;其中有很多也可以應用到 Raft 中來,但是我們暫時把這個問題放到未來的工作中去。

我們使用我們自己的 Raft 實現來衡量 Raft 領導人選舉的效能並且回答兩個問題。首先,領導人選舉的過程收斂是否快速?第二,在領導人當機之後,最小的系統當機時間是多久?

圖 16

圖 16:發現並替換一個已經崩潰的領導人的時間。上面的圖考察了在選舉超時時間上的隨機化程度,下面的圖考察了最小選舉超時時間。每條線代表了 1000 次實驗(除了 150-150 毫秒只試了 100 次),和相應的確定的選舉超時時間。例如,150-155 毫秒意思是,選舉超時時間從這個區間範圍內隨機選擇並確定下來。這個實驗在一個擁有 5 個節點的叢集上進行,其廣播時延大約是 15 毫秒。對於 9 個節點的叢集,結果也差不多。

為了衡量領導人選舉,我們反覆的使一個擁有五個節點的伺服器叢集的領導人當機,並計算需要多久才能發現領導人已經當機並選出一個新的領導人(見圖 16)。為了構建一個最壞的場景,在每一的嘗試裡,伺服器都有不同長度的日誌,意味著有些候選人是沒有成為領導人的資格的。另外,為了促成選票瓜分的情況,我們的測試指令碼在終止領導人之前同步的傳送了一次心跳廣播(這大約和領導人在崩潰前複製一個新的日誌給其他機器很像)。領導人均勻的隨機的在心跳間隔裡當機,也就是最小選舉超時時間的一半。因此,最小當機時間大約就是最小選舉超時時間的一半。

圖 16 中上面的圖表明,只需要在選舉超時時間上使用很少的隨機化就可以大大避免選票被瓜分的情況。在沒有隨機化的情況下,在我們的測試裡,選舉過程往往都需要花費超過 10 秒鐘由於太多的選票瓜分的情況。僅僅增加 5 毫秒的隨機化時間,就大大的改善了選舉過程,現在平均的當機時間只有 287 毫秒。增加更多的隨機化時間可以大大改善最壞情況:通過增加 50 毫秒的隨機化時間,最壞的完成情況(1000 次嘗試)只要 513 毫秒。

圖 16 中下面的圖顯示,通過減少選舉超時時間可以減少系統的當機時間。在選舉超時時間為 12-24 毫秒的情況下,只需要平均 35 毫秒就可以選舉出新的領導人(最長的一次花費了 152 毫秒)。然而,進一步降低選舉超時時間的話就會違反 Raft 的時間不等式需求:在選舉新領導人之前,領導人就很難傳送完心跳包。這會導致沒有意義的領導人改變並降低了系統整體的可用性。我們建議使用更為保守的選舉超時時間,比如 150-300 毫秒;這樣的時間不大可能導致沒有意義的領導人改變,而且依然提供不錯的可用性。

10 相關工作

已經有很多關於一致性演算法的工作被髮表出來,其中很多都可以歸到下面的類別中:

  • Lamport 關於 Paxos 的原始描述,和嘗試描述的更清晰。
  • 關於 Paxos 的更詳盡的描述,補充遺漏的細節並修改演算法,使得可以提供更加容易的實現基礎。
  • 實現一致性演算法的系統,例如 Chubby,ZooKeeper 和 Spanner。對於 Chubby 和 Spanner 的演算法並沒有公開發表其技術細節,儘管他們都聲稱是基於 Paxos 的。ZooKeeper 的演算法細節已經發表,但是和 Paxos 著實有著很大的差別。
  • Paxos 可以應用的效能優化。
  • Oki 和 Liskov 的 Viewstamped Replication(VR),一種和 Paxos 差不多的替代演算法。原始的演算法描述和分散式傳輸協議耦合在了一起,但是核心的一致性演算法在最近的更新裡被分離了出來。VR 使用了一種基於領導人的方法,和 Raft 有很多相似之處。

Raft 和 Paxos 最大的不同之處就在於 Raft 的強領導特性:Raft 使用領導人選舉作為一致性協議裡必不可少的部分,並且將盡可能多的功能集中到了領導人身上。這樣就可以使得演算法更加容易理解。例如,在 Paxos 中,領導人選舉和基本的一致性協議是正交的:領導人選舉僅僅是效能優化的手段,而且不是一致性所必須要求的。但是,這樣就增加了多餘的機制:Paxos 同時包含了針對基本一致性要求的兩階段提交協議和針對領導人選舉的獨立的機制。相比較而言,Raft 就直接將領導人選舉納入到一致性演算法中,並作為兩階段一致性的第一步。這樣就減少了很多機制。

像 Raft 一樣,VR 和 ZooKeeper 也是基於領導人的,因此他們也擁有一些 Raft 的優點。但是,Raft 比 VR 和 ZooKeeper 擁有更少的機制因為 Raft 儘可能的減少了非領導人的功能。例如,Raft 中日誌條目都遵循著從領導人傳送給其他人這一個方向:附加條目 RPC 是向外傳送的。在 VR 中,日誌條目的流動是雙向的(領導人可以在選舉過程中接收日誌);這就導致了額外的機制和複雜性。根據 ZooKeeper 公開的資料看,它的日誌條目也是雙向傳輸的,但是它的實現更像 Raft。

和上述我們提及的其他基於一致性的日誌複製演算法中,Raft 的訊息型別更少。例如,我們數了一下 VR 和 ZooKeeper 使用的用來基本一致性需要和成員改變的訊息數(排除了日誌壓縮和客戶端互動,因為這些都比較獨立且和演算法關係不大)。VR 和 ZooKeeper 都分別定義了 10 中不同的訊息型別,相對的,Raft 只有 4 中訊息型別(兩種 RPC 請求和對應的響應)。Raft 的訊息都稍微比其他演算法的要資訊量大,但是都很簡單。另外,VR 和 ZooKeeper 都在領導人改變時傳輸了整個日誌;所以為了能夠實踐中使用,額外的訊息型別就很必要了。

Raft 的強領導人模型簡化了整個演算法,但是同時也排斥了一些效能優化的方法。例如,平等主義 Paxos (EPaxos)在某些沒有領導人的情況下可以達到很高的效能。平等主義 Paxos 充分發揮了在狀態機指令中的交換性。任何伺服器都可以在一輪通訊下就提交指令,除非其他指令同時被提出了。然而,如果指令都是併發的被提出,並且互相之間不通訊溝通,那麼 EPaxos 就需要額外的一輪通訊。因為任何伺服器都可以提交指令,所以 EPaxos 在伺服器之間的負載均衡做的很好,並且很容易在 WAN 網路環境下獲得很低的延遲。但是,他在 Paxos 上增加了非常明顯的複雜性。

一些叢集成員變換的方法已經被提出或者在其他的工作中被實現,包括 Lamport 的原始的討論,VR 和 SMART。我們選擇使用共同一致的方法因為他對一致性協議的其他部分影響很小,這樣我們只需要很少的一些機制就可以實現成員變換。Lamport 的基於 α 的方法之所以沒有被 Raft 選擇是因為它假設在沒有領導人的情況下也可以達到一致性。和 VR 和 SMART 相比較,Raft 的重新配置演算法可以在不限制正常請求處理的情況下進行;相比較的,VR 需要停止所有的處理過程,SMART 引入了一個和 α 類似的方法,限制了請求處理的數量。Raft 的方法同時也需要更少的額外機制來實現,和 VR、SMART 比較而言。

11 結論

演算法的設計通常會把正確性,效率或者簡潔作為主要的目標。儘管這些都是很有意義的目標,但是我們相信,可理解性也是一樣的重要。在開發者把演算法應用到實際的系統中之前,這些目標沒有一個會被實現,這些都會必然的偏離發表時的形式。除非開發人員對這個演算法有著很深的理解並且有著直觀的感覺,否則將會對他們而言很難在實現的時候保持原有期望的特性。

在這篇論文中,我們嘗試解決分散式一致性問題,但是一個廣為接受但是十分令人費解的演算法 Paxos 已經困擾了無數學生和開發者很多年了。我們創造了一種新的演算法 Raft,顯而易見的比 Paxos 要容易理解。我們同時也相信,Raft 也可以為實際的實現提供堅實的基礎。把可理解性作為設計的目標改變了我們設計 Raft 的方式;隨著設計的進展,我們發現自己重複使用了一些技術,比如分解問題和簡化狀態空間。這些技術不僅提升了 Raft 的可理解性,同時也使我們堅信其正確性。

12 感謝

這項研究必須感謝以下人員的支援:Ali Ghodsi,David Mazie`res,和伯克利 CS 294-91 課程、史丹佛 CS 240 課程的學生。Scott Klemmer 幫我們設計了使用者調查,Nelson Ray 建議我們進行統計學的分析。在使用者調查時使用的關於 Paxos 的幻燈片很大一部分是從 Lorenzo Alvisi 的幻燈片上借鑑過來的。特別的,非常感謝 DavidMazieres 和 Ezra Hoch,他們找到了 Raft 中一些難以發現的漏洞。許多人提供了關於這篇論文十分有用的反饋和使用者調查材料,包括 Ed Bugnion,Michael Chan,Hugues Evrard,Daniel Giffin,Arjun Gopalan,Jon Howell,Vimalkumar Jeyakumar,Ankita Kejriwal,Aleksandar Kracun,Amit Levy,Joel Martin,Satoshi Matsushita,Oleg Pesok,David Ramos,Robbert van Renesse,Mendel Rosenblum,Nicolas Schiper,Deian Stefan,Andrew Stone,Ryan Stutsman,David Terei,Stephen Yang,Matei Zaharia 以及 24 位匿名的會議審查人員(可能有重複),並且特別感謝我們的領導人 Eddie Kohler。Werner Vogels 發了一條早期草稿連結的推特,給 Raft 帶來了極大的關注。我們的工作由 Gigascale 系統研究中心和 Multiscale 系統研究中心給予支援,這兩個研究中心由關注中心研究程式資金支援,一個是半導體研究公司的程式,由 STARnet 支援,一個半導體研究公司的程式由 MARCO 和 DARPA 支援,在國家科學基金會的 0963859 號批准,並且獲得了來自 Facebook,Google,Mellanox,NEC,NetApp,SAP 和 Samsung 的支援。Diego Ongaro 由 Junglee 公司,史丹佛的畢業團體支援。

本文經TopJohn授權轉自TopJohn's Blog

深入淺出區塊鏈 - 系統學習區塊鏈,打造最好的區塊鏈技術部落格。

相關文章