<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          Paxos 分布式必問的內(nèi)容,沒有之一

          共 5755字,需瀏覽 12分鐘

           ·

          2020-10-07 09:46

          Google Chubby 的作者 Mike Burrows 說過:There is only one consensus protocol, and that's Paxos.

          引言

          上文我們已經(jīng)詳細的闡述了共識問題并介紹了一些共識算法,其中 Paxos 算法是 Leslie Lamport 于 1990 年提出的共識算法,不幸的是采用希臘民主議會的比喻很明顯失敗了,Lamport 像寫小說一樣,把一個復雜的數(shù)學問題弄成了一篇帶有考古色彩的歷史小說。根據(jù)?Lamport 自己的描述[1],三個審稿者都認為該論文盡管并不重要但還有些意思,只是應該把其中所有 Paxos 相關(guān)的故事背景刪掉。Lamport 對這些缺乏幽默感的人感到生氣,所以他不打算對論文做任何修改。

          多年后,兩個在 SRC(Systems Research Center,DEC 于 1984 年創(chuàng)立,Lamport 也曾在此工作過)工作的人需要為他們正在構(gòu)建的分布式系統(tǒng)尋找一些合適算法,而 Paxos 恰恰提供了他們想要的。Lamport 就將論文發(fā)給他們,他們也沒覺得該論文有什么問題。

          因此,Lamport 覺得論文重新發(fā)表的時間到了,"The Part-Time Parliament[2]" 最終在 1998 年公開發(fā)表。

          可是很多人抱怨這篇論文根本看不懂啊,人們只記住了那個奇怪的故事,而不是 Paxos 算法。Lamport 走到哪都要被人抱怨一通。于是他忍無可忍,2001 年重新發(fā)表了一篇關(guān)于 Paxos 的論文——"Paxos Made Simple[3]",這次論文中一個公式也沒有,摘要也只有一句話:

          The Paxos algorithm, when presented in plain English, is very simple.

          滿滿的都是嘲諷!

          然而,可能是表述順序的原因,這篇論文還是非常難以理解,于是人們寫了一系列文章來解釋這篇論文(重復造論文),以及在工程上如何實現(xiàn)它。

          其中,個人認為講解 Paxos 最好的視頻[4]來自于 Raft 算法作者 Diego Ongaro,本文采用 Diego 講義中的圖片來理解 Paxos 算法,也糾正了一個個人認為 Diego 筆誤的地方。

          術(shù)語

          基本概念

          ?Proposal Value:提案的值;?Proposal Number:提案編號;?Proposal:提案 = 提案編號 + 提案的值;?Chosen:批準,也叫選定。一旦某個值被 Chosen,后續(xù) Paxos 都必須用該值進行交互。

          注:Proposal 有人叫“提議”有人叫“提案”,此處和維基百科里的翻譯保持一致,叫“提案”。

          角色

          ?Proposer:提案發(fā)起者;?Acceptor:提案接收者;?Learner:提案學習者;

          問題描述

          為了高可用性,一種常見的設(shè)計是用一個 master 節(jié)點來寫,然后復制到各個 slave 節(jié)點。這種解決方法的問題在于,一旦 master 節(jié)點故障,整個服務將不可用或者數(shù)據(jù)不一致。

          為了克服單點寫入問題,于是有了多數(shù)派(Quorum)寫,思路就是寫入一半以上的節(jié)點。即,如果集群中有 N 個節(jié)點,客戶端需要寫入 W >= N/2 + 1 個節(jié)點。不需要主節(jié)點。這種方法可以容忍最多 (N-1)/2 個節(jié)點故障。

          但是問題依然存在:每個接收者該如何決定是否接受這次請求的值呢?

          如果我們接受第一次收到的值,那么當出現(xiàn)以下情況(Split Votes),則沒有出現(xiàn)多數(shù)派,沒有一個值被 Chosen,算法無法終止,這違反了活性(liveness)。



          為了解決 Split Votes 問題,我們允許接受多個不同的值,收到的每一個(every)請求都接受,這時候新的問題出現(xiàn)了,如下,可能不止一個值被 Chosen,這違反了安全性(safety)



          注意,Paxos 強調(diào):

          Once a value has been chosen, future proposals must propose the same value.

          也就是說,我們討論的 Basic-Paxos 只會 Chosen 一個值?;诖?,就需要一個兩階段(2-phase)協(xié)議,對于已經(jīng) Chosen 的值,后面的提案也要使用相同的值。

          如下圖這種情況,S3 直接拒絕?red?值,因為?blue?已經(jīng) Chosen,這樣就可以保證成功。



          這種方式我們需要對提案進行排序。如果你熟悉分布式系統(tǒng),應該能想到 "Time, Clocks and the Ordering of Events in a Distributed System[5]" 這篇論文,我們不能用時間來判斷提案的先后順序。

          Proposal Number

          一種簡單的方式就是每個請求一個唯一的編號,例如:,為了排序?seq_id?是自增的;同時為了避免崩潰重啟,必須能在本地持久化存儲。

          Paxos

          現(xiàn)在我們終于可以開始描述 Paxos 算法了。

          如上所述,Paxos 是一個兩階段算法。我們把第一個階段叫做準備(Prepare)階段,第二個階段叫做接受(Accept)階段。分別對應兩輪 RPC。

          第一輪 Prepare RPCs:

          請求(也叫 Prepare 階段):

          Proposer 選擇一個提案編號 n,向所有的 Acceptor 廣播?Prepare(n)?請求。

          這里 Prepare(n)不包含提案的值。

          偽代碼:

          send PREPARE(++n)

          響應(也叫 PROMISE 階段):

          Acceptor 接收到?Prepare(n)?請求,此時有兩種情況:

          ?如果 n 大于之前接受到的所有 Prepare 請求的編號,則返回?Promise()?響應,并承諾將不會接收編號小于 n 的提案。如果有提案被 Chosen 的話,Promise()?響應還應包含前一次提案編號和對應的值。?否則(即 n 小于等于 Acceptor 之前收到的最大編號)忽略,但常常會回復一個拒絕響應。

          所以,Acceptor 需要持久化存儲 max_n、accepted_N 和 accepted_VALUE

          偽代碼:

          if (n > max_n)    max_n = n     // save highest n we've seen so far    if (proposal_accepted == true) // was a proposal already accepted?        respond: PROMISE(n, accepted_N, accepted_VALUE)    else        respond: PROMISE(n)else    do not respond (or respond with a "fail" message)

          第二輪 Accept RPCs:

          請求(也叫 PROPOSE 階段):

          當 Proposer 收到超過半數(shù) Acceptor?的?Promise()?響應后,Proposer 向多數(shù)派的 Acceptor 發(fā)起?Accept(n, value)?請求并帶上提案編號和值。(注:這里講義的算法流程圖是向所有的 Acceptor 發(fā)起?Accept()?請求,鄙人認為應該改為向多數(shù)派 Acceptor 發(fā)起。)

          注意:Proposer 不一定是將?Accept()?請求發(fā)給有應答的多數(shù)派 Acceptors,可以再選另一個多數(shù)派 Acceptors 廣播?Accept()?請求。

          關(guān)于值 value 的選擇:如果前面的 Promise 響應有返回?accepted_VALUE,那就使用這個值作為 value。如果沒有返回?accepted_VALUE,那可以自由決定提案值 value。

          偽代碼:

          did I receive PROMISE responses from a majority of acceptors?if yes    do any responses contain accepted values (from other proposals)?    if yes        val = accepted_VALUE    // value from PROMISE message with the highest accepted ID    if no        val = VALUE     // we can use our proposed value    send Accept(ID, val) to at least a majority of acceptors

          響應(也叫 ACCEPT 階段):

          Acceptor 收到?Accept()?請求,在這期間如果 Acceptor 沒有對比 n 更大的編號另行 Promise,則接受該提案。

          偽代碼:

          if (n >= max_n) // is the n the largest I have seen so far?    proposal_accepted = true     // note that we accepted a proposal    accepted_N = n             // save the accepted proposal number    accepted_VALUE = VALUE       // save the accepted proposal data    respond: Accepted(N, VALUE) to the proposer and all learnerselse    do not respond (or respond with a "fail" message)

          一些例子

          情況 1:提案已 Chosen


          1.S1 收到客戶端提案請求 X,于是 S1 向 S1-S3 發(fā)起?Prepare(3.1)?請求,PROMISE()?響應返回沒有提案被 Chosen2.由于 S1-S3 沒有任何提案被 Chosen,S1 繼續(xù)向 S1-S3 發(fā)送?Accept(3.1, X)?請求,提案被成功 Chosen3.在提案被 Chosen 后,S5 收到客戶端提案值為 Y 的請求,向 S3-S5 發(fā)送?Prepare(4.5)?請求,由于編號 4 > 3 會收到提案值為 X 已經(jīng)被 Chosen 的?PROMISE()?響應4.于是 S5?將提案值 Y 替換成 X,向 S1-S3 發(fā)送?Accept(4.5, X)?請求,提案再次被 Chosen

          情況 2:提案未 Chosen,Proposer 可見


          情況 2 和情況 1 類似,在 S3 Chosen 了提案后,S5 收到來自 S3 的?PROMISE()?響應包含了已經(jīng) Chosen 的提案值 X,所以同樣會將提案值替換成 X,最終所有 Acceptor 對 X 達成共識。

          注意上面的偽代碼:do any responses contain accepted values,也就是說只要有一個 Acceptor 在?Promise()?響應中返回了提案值,就要用它來替換提案值。

          情況 3:提案未提交,Proposer 不可見


          情況 3 中,提案只被 S1 Chosen,S3 還未 Chosen 該提案,S3-S5 的?Promise()?響應中沒有任何提案信息,所以 S5 自行決定提案值為 Y,發(fā)送?Accept(4.5, Y)?請求。

          由于此時 S3 承諾的提案編號 n 變?yōu)榱?4 且 4 大于 3,所以 S3 不再接受 S1 后續(xù)的?Accept(3.1, X)?請求。提案值 X 被阻止,而提案值 Y 最終被 Chosen。

          活鎖


          如圖:當 Proposer 在第一輪 Prepare 發(fā)出請求,還沒來得及后續(xù)的第二輪 Accept 請求,緊接著第二個 Proposer 在第一階段也發(fā)出編號更大的請求。如果這樣無窮無盡,Acceptor 始終停留在決定順序號的過程上,那大家誰也成功不了。

          解決活鎖最簡單的方式就是引入隨機超時,這樣可以讓某個 Proposer 先進行提案,減少一直互相搶占的可能。

          結(jié)語

          Paxos 只從一個或多個值中選擇一個值,如果需要重復運行 Paxos 來創(chuàng)建復制狀態(tài)機,我們稱之為 multi-Paxos,但如果每個命令都通過一個Basic Paxos算法實例來達到一致,會產(chǎn)生大量開銷。對于 multi-Paxos 可以做一些優(yōu)化,我們在下篇文章中討論 Paxos 的變種。

          References

          [1]?Lamport 自己的描述:?http://lamport.azurewebsites.net/pubs/pubs.html#lamport-paxos
          [2]?The Part-Time Parliament:?https://lamport.azurewebsites.net/pubs/lamport-paxos.pdf
          [3]?Paxos Made Simple:?https://lamport.azurewebsites.net/pubs/paxos-simple.pdf
          [4]?視頻:?https://www.youtube.com/watch?v=JEpsBg0AO6o
          [5]?Time, Clocks and the Ordering of Events in a Distributed System:?http://lamport.azurewebsites.net/pubs/time-clocks.pdf


          后臺回復?學習資料?領(lǐng)取學習視頻


          如有收獲,點個在看,誠摯感謝

          瀏覽 49
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  亚洲成人18禁 | 五月天成人综合 | 91资源在线播放 | 日韩欧美在线第一页 | 想xx视频 |