分布式一致性算法——Paxos原理與推導過程

Paxos算法在分布式領域具有非常重要的地位。但是Paxos算法有兩個比較明顯的缺點:1.難以理解 2.工程實現更難。

網上有很多講解Paxos算法的文章,但是質量參差不齊。看了很多關于Paxos的資料后發現,學習Paxos最好的資料是論文《Paxos Made Simple》,其次是中、英文版維基百科對Paxos的介紹。本文試圖帶大家一步步揭開Paxos神秘的面紗。

Paxos是什么

Paxos算法是基于消息傳遞且具有高度容錯特性一致性算法,是目前公認的解決分布式一致性問題最有效的算法之一。

Google Chubby的作者Mike Burrows說過這個世界上只有一種一致性算法,那就是Paxos,其它的算法都是殘次品

雖然Mike Burrows說得有點夸張,但是至少說明了Paxos算法的地位。然而,Paxos算法也因為晦澀難懂而臭名昭著。本文的目的就是帶領大家深入淺出理解Paxos算法,不僅理解它的執行流程,還要理解算法的推導過程,作者是怎么一步步想到最終的方案的。只有理解了推導過程,才能深刻掌握該算法的精髓。而且理解推導過程對于我們的思維也是非常有幫助的,可能會給我們帶來一些解決問題的思路,對我們有所啟發。

問題產生的背景

在常見的分布式系統中,總會發生諸如機器宕機網絡異常(包括消息的延遲、丟失、重復、亂序,還有網絡分區)等情況。Paxos算法需要解決的問題就是如何在一個可能發生上述異常的分布式系統中,快速且正確地在集群內部對某個數據的值達成一致,并且保證不論發生以上任何異常,都不會破壞整個系統的一致性。

注:這里某個數據的值并不只是狹義上的某個數,它可以是一條日志,也可以是一條命令(command)。。。根據應用場景不同,某個數據的值有不同的含義。

問題產生的背景

相關概念

在Paxos算法中,有三種角色:

  • Proposer
  • Acceptor
  • Learners

在具體的實現中,一個進程可能同時充當多種角色。比如一個進程可能既是Proposer又是Acceptor又是Learner

還有一個很重要的概念叫提案(Proposal)。最終要達成一致的value就在提案里。

注:

  • 暫且認為『提案=value』,即提案只包含value。在我們接下來的推導過程中會發現如果提案只包含value,會有問題,于是我們再對提案重新設計
  • 暫且認為『Proposer可以直接提出提案』。在我們接下來的推導過程中會發現如果Proposer直接提出提案會有問題,需要增加一個學習提案的過程。

Proposer可以提出(propose)提案;Acceptor可以接受(accept)提案;如果某個提案被選定(chosen),那么該提案里的value就被選定了。

回到剛剛說的『對某個數據的值達成一致』,指的是Proposer、Acceptor、Learner都認為同一個value被選定(chosen)。那么,Proposer、Acceptor、Learner分別在什么情況下才能認為某個value被選定呢?

  • Proposer:只要Proposer發的提案被Acceptor接受(剛開始先認為只需要一個Acceptor接受即可,在推導過程中會發現需要半數以上的Acceptor同意才行),Proposer就認為該提案里的value被選定了。
  • Acceptor:只要Acceptor接受了某個提案,Acceptor就任務該提案里的value被選定了。
  • Learner:Acceptor告訴Learner哪個value被選定,Learner就認為那個value被選定。
相關概念

問題描述

假設有一組可以提出(propose)value(value在提案Proposal里)的進程集合。一個一致性算法需要保證提出的這么多value中,只有一個value被選定(chosen)。如果沒有value被提出,就不應該有value被選定。如果一個value被選定,那么所有進程都應該能學習(learn)到這個被選定的value。對于一致性算法,安全性(safaty)要求如下:

  • 只有被提出的value才能被選定。
  • 只有一個value被選定,并且
  • 如果某個進程認為某個value被選定了,那么這個value必須是真的被選定的那個。

我們不去精確地定義其活性(liveness)要求。我們的目標是保證最終有一個提出的value被選定。當一個value被選定后,進程最終也能學習到這個value。

Paxos的目標:保證最終有一個value會被選定,當value被選定后,進程最終也能獲取到被選定的value。

假設不同角色之間可以通過發送消息來進行通信,那么:

  • 每個角色以任意的速度執行,可能因出錯而停止,也可能會重啟。一個value被選定后,所有的角色可能失敗然后重啟,除非那些失敗后重啟的角色能記錄某些信息,否則等他們重啟后無法確定被選定的值。
  • 消息在傳遞過程中可能出現任意時長的延遲,可能會重復,也可能丟失。但是消息不會被損壞,即消息內容不會被篡改(拜占庭將軍問題)。

推導過程

最簡單的方案——只有一個Acceptor

假設只有一個Acceptor(可以有多個Proposer),只要Acceptor接受它收到的第一個提案,則該提案被選定,該提案里的value就是被選定的value。這樣就保證只有一個value會被選定。

但是,如果這個唯一的Acceptor宕機了,那么整個系統就無法工作了!

因此,必須要有多個Acceptor

只有一個Acceptor

多個Acceptor

多個Acceptor的情況如下圖。那么,如何保證在多個Proposer和多個Acceptor的情況下選定一個value呢?

多個Acceptor

下面開始尋找解決方案。

如果我們希望即使只有一個Proposer提出了一個value,該value也最終被選定。

那么,就得到下面的約束:

P1:一個Acceptor必須接受它收到的第一個提案。

但是,這又會引出另一個問題:如果每個Proposer分別提出不同的value,發給不同的Acceptor。根據P1,Acceptor分別接受自己收到的value,就導致不同的value被選定。出現了不一致。如下圖:

幻燈片08.png

剛剛是因為『一個提案只要被一個Acceptor接受,則該提案的value就被選定了』才導致了出現上面不一致的問題。因此,我們需要加一個規定:

規定:一個提案被選定需要被半數以上的Acceptor接受

這個規定又暗示了:『一個Acceptor必須能夠接受不止一個提案!』不然可能導致最終沒有value被選定。比如上圖的情況。v1、v2、v3都沒有被選定,因為它們都只被一個Acceptor的接受。

最開始講的『提案=value』已經不能滿足需求了,于是重新設計提案,給每個提案加上一個提案編號,表示提案被提出的順序。令『提案=提案編號+value』。

雖然允許多個提案被選定,但必須保證所有被選定的提案都具有相同的value值。否則又會出現不一致。

于是有了下面的約束:

P2:如果某個value為v的提案被選定了,那么每個編號更高的被選定提案的value必須也是v。

一個提案只有被Acceptor接受才可能被選定,因此我們可以把P2約束改寫成對Acceptor接受的提案的約束P2a。

P2a:如果某個value為v的提案被選定了,那么每個編號更高的被Acceptor接受的提案的value必須也是v。

只要滿足了P2a,就能滿足P2。

但是,考慮如下的情況:假設總共有5個Acceptor。Proposer2提出[M1,V1]的提案,Acceptor25(半數以上)均接受了該提案,于是對于Acceptor25和Proposer2來講,它們都認為V1被選定。Acceptor1剛剛從宕機狀態恢復過來(之前Acceptor1沒有收到過任何提案),此時Proposer1向Acceptor1發送了[M2,V2]的提案(V2≠V1且M2>M1),對于Acceptor1來講,這是它收到的第一個提案。根據P1(一個Acceptor必須接受它收到的第一個提案。),Acceptor1必須接受該提案!同時Acceptor1認為V2被選定。這就出現了兩個問題:

  1. Acceptor1認為V2被選定,Acceptor2~5和Proposer2認為V1被選定。出現了不一致。
  2. V1被選定了,但是編號更高的被Acceptor1接受的提案[M2,V2]的value為V2,且V2≠V1。這就跟P2a(如果某個value為v的提案被選定了,那么每個編號更高的被Acceptor接受的提案的value必須也是v)矛盾了。
幻燈片10.png

所以我們要對P2a約束進行強化!

P2a是對Acceptor接受的提案約束,但其實提案是Proposer提出來的,所以我們可以對Proposer提出的提案進行約束。得到P2b:

P2b:如果某個value為v的提案被選定了,那么之后任何Proposer提出的編號更高的提案的value必須也是v。

由P2b可以推出P2a進而推出P2。

那么,如何確保在某個value為v的提案被選定后,Proposer提出的編號更高的提案的value都是v呢?

只要滿足P2c即可:

P2c:對于任意的N和V,如果提案[N, V]被提出,那么存在一個半數以上的Acceptor組成的集合S,滿足以下兩個條件中的任意一個:

  • S中每個Acceptor都沒有接受過編號小于N的提案。
  • S中Acceptor接受過的最大編號的提案的value為V。

Proposer生成提案

為了滿足P2b,這里有個比較重要的思想:Proposer生成提案之前,應該先去『學習』已經被選定或者可能被選定的value,然后以該value作為自己提出的提案的value。如果沒有value被選定,Proposer才可以自己決定value的值。這樣才能達成一致。這個學習的階段是通過一個『Prepare請求』實現的。

于是我們得到了如下的提案生成算法

  1. Proposer選擇一個新的提案編號N,然后向某個Acceptor集合(半數以上)發送請求,要求該集合中的每個Acceptor做出如下響應(response)。
    (a) 向Proposer承諾保證不再接受任何編號小于N的提案
    (b) 如果Acceptor已經接受過提案,那么就向Proposer響應已經接受過的編號小于N的最大編號的提案

    我們將該請求稱為編號為NPrepare請求

  2. 如果Proposer收到了半數以上的Acceptor的響應,那么它就可以生成編號為N,Value為V的提案[N,V]。這里的V是所有的響應中編號最大的提案的Value。如果所有的響應中都沒有提案,那 么此時V就可以由Proposer自己選擇
    生成提案后,Proposer將該提案發送給半數以上的Acceptor集合,并期望這些Acceptor能接受該提案。我們稱該請求為Accept請求。(注意:此時接受Accept請求的Acceptor集合不一定是之前響應Prepare請求的Acceptor集合)

Acceptor接受提案

Acceptor可以忽略任何請求(包括Prepare請求和Accept請求)而不用擔心破壞算法的安全性。因此,我們這里要討論的是什么時候Acceptor可以響應一個請求。

我們對Acceptor接受提案給出如下約束:

P1a:一個Acceptor只要尚未響應過任何編號大于NPrepare請求,那么他就可以接受這個編號為N的提案

如果Acceptor收到一個編號為N的Prepare請求,在此之前它已經響應過編號大于N的Prepare請求。根據P1a,該Acceptor不可能接受編號為N的提案。因此,該Acceptor可以忽略編號為N的Prepare請求。當然,也可以回復一個error,讓Proposer盡早知道自己的提案不會被接受。

因此,一個Acceptor只需記住:1. 已接受的編號最大的提案 2. 已響應的請求的最大編號。

小優化

Paxos算法描述

經過上面的推導,我們總結下Paxos算法的流程。

Paxos算法分為兩個階段。具體如下:

  • 階段一:

    (a) Proposer選擇一個提案編號N,然后向半數以上的Acceptor發送編號為N的Prepare請求

    (b) 如果一個Acceptor收到一個編號為N的Prepare請求,且N大于該Acceptor已經響應過的所有Prepare請求的編號,那么它就會將它已經接受過的編號最大的提案(如果有的話)作為響應反饋給Proposer,同時該Acceptor承諾不再接受任何編號小于N的提案

  • 階段二:

    (a) 如果Proposer收到半數以上Acceptor對其發出的編號為N的Prepare請求的響應,那么它就會發送一個針對[N,V]提案Accept請求半數以上的Acceptor。注意:V就是收到的響應編號最大的提案的value,如果響應中不包含任何提案,那么V就由Proposer自己決定

    (b) 如果Acceptor收到一個針對編號為N的提案的Accept請求,只要該Acceptor沒有對編號大于NPrepare請求做出過響應,它就接受該提案

Paxos算法流程

Learner學習被選定的value

Learner學習(獲取)被選定的value有如下三種方案:

Learner學習被選定的value

如何保證Paxos算法的活性

幻燈片18.png

通過選取主Proposer,就可以保證Paxos算法的活性。至此,我們得到一個既能保證安全性,又能保證活性分布式一致性算法——Paxos算法

參考資料

  • 論文《Paxos Made Simple》
  • 書籍《從Paxos到ZooKeeper》
  • 英文版維基百科的Paxos
  • 中文版維基百科的Paxos
  • 論文《The Part-Time Parliament》
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,333評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,491評論 3 416
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,263評論 0 374
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,946評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,708評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,186評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,255評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,409評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,939評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,774評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,976評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,518評論 5 359
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,209評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,641評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,872評論 1 286
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,650評論 3 391
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,958評論 2 373

推薦閱讀更多精彩內容

  • Paxos是什么 Paxos算法是基于消息傳遞且具有高度容錯特性的一致性算法,是目前公認的解決分布式一致性問題最有...
    jiangmo閱讀 1,547評論 0 6
  • 此文知識來自于:《從Paxos到Zookeeper分布式一致性原理與實踐》第二章分布式入門基礎知識,由于博主對其理...
    李文文丶閱讀 1,952評論 0 0
  • 持續更新 如何淺顯易懂地解說 Paxos 的算法? 參考資料 #8:知行學社的分布式系統與Paxos算法視頻課程,...
    xiewen閱讀 16,771評論 0 44
  • 原文:Paxos Made Simple作者:Leslie Lamport時間:01 Nov 2001 1 Int...
    隨安居士閱讀 1,579評論 1 2
  • 1.來源 Paxos算法是萊斯利·蘭伯特(Leslie Lamport)于1990年提出的一種基于消息傳遞的一致性...
    Lane0x閱讀 915評論 0 3