Paxos 算法淺析

持續更新

如何淺顯易懂地解說 Paxos 的算法?

參考資料 #8:知行學社的分布式系統與Paxos算法視頻課程,循序漸進,講解得比較淺顯易懂

Paxos

背景

什么是 consensus (一致性)問題?
在一個分布式系統中,有一組的 process,每個 process 都可以提出一個 value,consensus 算法就是用來從這些 values 里選定一個最終 value。如果沒有 value 被提出來,那么就沒有 value 被選中;如果有1個 value 被選中,那么所有的 process 都應該被通知到。
上面問題看上去很好解決,比如用一個 master,所有 process 都向這個 master 提交 value,這個 master 可以根據先到的原則選擇最先到達的 value 為最終 value 并通知給所有 process。這里有個問題,如果這個 master 斷了、當機、重啟、崩潰了怎么辦?所以一個好的方法就是選擇一組 masters,value 由這一組 masters 共同決定,有點像 ”議會“。為了解決這個問題,大家提出了各種各樣的 protocols(協議),其中最有名的就是 Lamport 的 Paxos.

Icon

Paxos is a consensus algorithm executed by a set of processes, termed replicas, to agree on a single value in the presence of failures.
Paxos算法解決的問題是在一個可能發生異常(進程可能會慢、被殺死或者重啟,消息可能會延遲、丟失、重復,不考慮消息篡改即拜占庭錯誤的情況)的分布式系統中如何就某個值達成一致,保證不論發生以上任何異常,都不會破壞決議的一致性。

Paxos協議提出只要系統中2f+1個節點中的f+1個節點可用,那么系統整體就可用并且能保證數據的強一致性,它對于可用性的提升是極大的。

Paxos協議由Leslie Lamport最早在1990年提出,由于Paxos在云計算領域的廣泛應用Leslie Lamport因此獲得了2013年度圖靈獎。

算法

Leslie寫的兩篇論文:《The Part-Time Parliament》和《Paxos Made Simple》比較完整的闡述了Paxos的工作流程和證明過程,Paxos協議把每個數據寫請求比喻成一次提案(proposal),每個提案都有一個獨立的編號,提案會轉發到提交者(Proposer)來提交,提案必須經過投票委員會(Quorum)接受才會生效,投票委員會中的節點叫做Acceptor。

角色分為proposers,acceptors(允許身兼數職)
proposers提出提案,提案信息包括提案編號和提議的value
acceptor收到提案后可以接受(accept)提案,若提案獲得多數acceptors的接受,則稱該提案被批準(chosen)

Paxos協議流程劃分為兩個階段,第一階段是Proposer學習提案最新狀態的準備階段;第二階段是根據學習到的狀態組成正確提案提交的階段,完整的協議過程如下:

  1. prepare 階段:
    1a) proposer選擇一個提案編號n并將prepare請求發送給acceptors中的一個多數派;
    1b) acceptor收到prepare消息后,如果提案的編號大于它已經回復的所有prepare消息,則acceptor將自己上次接受的提案回復給proposer,并承諾不再回復小于n的提案;

  2. accept 階段:
    2a) 當一個proposer收到了多數acceptors對prepare的回復后,就進入批準階段。它要向回復prepare請求的acceptors發送accept請求,包括編號n和根據P2c決定的value(如果根據P2c沒有已經接受的value,那么它可以自由決定value)。
    2b) 在不違背自己向其他proposer的承諾的前提下,acceptor收到accept請求后即接受這個請求。

這個過程在任何時候中斷都可以保證正確性。例如如果一個proposer發現已經有其他proposers提出了編號更高的提案,則有必要中斷這個過程。

P2c:如果一個編號為n的提案具有value v,那么存在一個多數派,要么他們中所有人都沒有接受(accept)編號小于n 的任何提案,要么他們已經接受(accept)的所有編號小于n的提案中編號最大的那個提案具有value v。


核心

可以簡單描述為:Proposer先從大多數Acceptor那里學習提案的最新內容,然后根據學習到的編號最大的提案內容組成新的提案提交,如果提案獲得大多數Acceptor的投票通過就意味著提案被通過。

由于學習提案和通過提案的Acceptor集合都超過了半數,所以一定能學到最新通過的提案值,兩次提案通過的Acceptor集合中也一定存在一個公共的Acceptor,在滿足約束條件b時這個公共的Acceptor時保證了數據的一致性,于是Paxos協議又被稱為多數派協議。

算法本質上很簡單,保證一致性所依賴的物理事實是:兩個多數集合至少有一個公共成員。把全局信息存儲在多數集合返回的統計結果上。

如果一個值曾經被通過了,多數集合中至少有一個成員記得它。

所以提議新值之前,先通過一個prepare階段就是從一個多數集合中收集到可能已經通過的值,并同步時鐘。

然后在accept階段就是發送可能已通過的值,或者在沒有值的情況下提議一個新值。

PaxosLease

PaxosLease 是 Kespace 開發的基于 Paxos、Lease 機制的 Master 選舉算法

由來

在Paxos中,如果能夠選舉出一個leader(在Lamport的論文中稱之為總統),那么有助于提高投票的成功率。另外這個leader在多個決議的選舉中有很重要的作用(要靠他得到決議的連續id)。因此,如何通過某種方法得到一個leader就是PaxosLease所說明的。

Master選舉的過程是這樣的:從眾多的Node中選擇一個作為Master,如果該Master 一直 alive則無需選舉,如果master crash,則其他的node進行選舉下一個master。選擇正確性的保證是:任何時刻最多只能有一個master。

邏輯上Master更像一把無形的鎖,任何一個節點拿到這個鎖,都可成為master,所以本質上Master選舉是個分布式鎖的問題,但完全靠鎖來解決選舉問題也是有風險的:如果一個Node拿到了鎖,之后crash,那鎖會導致無法釋放,即死鎖。一種可行的方案是給鎖加個時間(Lease),拿到鎖的Master只能在Lease有效期內訪問鎖定的資源,在Lease timeout后,其他Node可以繼續競爭鎖,這就從根本上避免了死鎖。

Master在拿到鎖后,如果一直alive,可以向其他node”續租“鎖,從而避免頻繁的選舉活動。

算法

算法過程略,詳見參考資料 #10:PaxosLease - 老碼農的專欄

1、算法的角色與Paxos一樣,也分Proposer、Acceptor、Learner,各角色的行為也與paxos基本一致。

2、accept 的 1a) 階段
原始的paxos規定,如果接收的value v不為空,則使用v繼續accept階段,以保證每次選舉僅選出一個決議;
PaxosLease選舉的目的是使其他node接受自己作為master,當接收的value不為空時,自己應該退出選舉,而不是繼續提交其他Node的value。也就是說,只要當前node知道其他Node可能會優先自己成為master,則退出選舉,成就他人。

3、Master選舉因為頻率低。PaxosLease在失敗重新提交proposal時隨機等待一段時間,因為各Node等待時間的不一致,只要運行足夠長的時間,活鎖總能避免。

4、重新加入的節點可能會擾亂前面的paxos過程,因此強制Node在重新加入前必須等待M秒,因為M > T,所以只要等待M秒便可以越過本次paxos選舉。其實不能從理論上完全保證PaxosLease能正確執行。重要的是重加入后不能立即參加paxos過程。在實際中因為選舉的過程非常快,節點重加入的過程也可監控,這些理論上的錯誤是很難發生的。
PaxosLease的正確性是有Paxos算法保證的,PaxosLease只是在Paxos的基礎上限定了一個時間。在時間T之內,任何Node都不能申請lease,因此master宕機后重新選擇master的最大時間為T,也即服務不可用的最大時間為T。
T設的過小會減少服務不可用的時間,但會產生更多的內部消息;設的過大內部消息減少,但會導致更長的宕機時間。
PaxosLease是一個節點之間不存在依賴的簡潔的選舉算法,就像其論文所說每個節點都有兩個狀態:
我不是master,也不知道誰是master
我是master
正因為如此,PaxosLease的缺點就是無法做到負載均衡,無法按權重選擇master。
Lease 機制
Lease機制是最重要的分布式協議,廣泛應用于各種實際的分布式系統中。
Lease通常定義為:頒發者在一定期限內給予持有者一定權利的協議。
Lease 表達了頒發者在一定期限內的承諾,只要未過期頒發者必須嚴格遵守 lease 約定的承諾;
Lease 的持有者在期限內使用頒發者的承諾,但 lease 一旦過期必須放棄使用或者重新和頒發者續約。

參考資料 #12

Multi-Paxos

paxos是對一個值達成一致,multi-paxos是運行多個paxos instance來對多個值達成一致,每個paxos instance對一個值達成一致。在一個支持多寫并且強一致性的系統中,每個節點都可以接收客戶端的寫請求,生成redo日志然后開始一個paxos instance的prepare和accept過程。這里的問題是每條redo日志到底對應哪個paxos instance。

Multi Paxos基于Basic Paxos,將原來2-Phase過程簡化為了1-Phase,從而加快了提交速度。Multi Paxos要求在各個Proposer中有唯一的Leader,并由這個Leader唯一地提交value給各Acceptor進行表決,在系統中僅有一個Leader進行value提交的情況下,Prepare的過程就可以被跳過,而Leader的選舉則可以由Paxos Lease來完成。

Fast Paxos

參考資料:#15

工程實踐的角度重新描述了Paxos,使其更貼近應用場景

就是Client的提案由Coordinator進行,Coordinator存在多個,但只能通過其中被選定Leader進行;提案由Leader交由Server進行表決,之后Client作為Learner學習決議的結果。
這種方式更多地考慮了Client/Server這種通用架構,更清楚地注意到了Client既作為Proposer又作為Learner這一事實。

下面是Classic Paxos交互圖:


下面是Fast Paxos的交互圖:


Fast Paxos基本是本著樂觀鎖的思路:如果存在沖突,則進行補償。其中Leader起到一個初始化Progress和解決沖突的作用,如果Progress一直執行良好,則Leader將始終不參與一致性過程。
因此Fast Paxos理論上只需要2個通信步驟,而Classic Paxos需要3個,但Fast Paxos在解決沖突時有至少需要1個通信步驟,在高并發的場景下,沖突的概率會非常高,沖突解決的成本也會很大。
另外,Fast Paxos把Client深度引入算法中,致使其架構遠沒Classic Paxos那么清晰,也沒Classic Paxos容易擴展。

實現

libpaxos

雖然libpaxos對PAXOS算法做了基礎的實現,但這個庫本身不能直接用于生產環境
采用的是libevent單線程reactor模型,無法利用充分利用多CPU的優勢,并發上會是個問題。另外,libpaxos并沒有實現PAXOS的leader模式。

libpaxos的主要價值是可以用來做研究,可以讓程序員對PAXOS的細節了解更加清楚
依賴 libevent 事件驅動、msgpack 序列化庫。

數據默認保存在內存,不持久化。也可支持持久化到 bdb 數據庫。

分為兩個部分
libpaxos 實現 Paxos 算法
libevpaxos 基于 libpaxos 和 libevent 的實現

KeySpace 中的 paxos

見參考資料 #11:Keyspace中的paxos - 老碼農的專欄

參考資料

1.https://zh.wikipedia.org/wiki/Paxos算法
2.paxos 算法的理解

  1. The Part-Time Parliament(Paxos算法)中文、英文
  2. Paxos Made Simple中文、英文
  3. Paxos Made Live中文英文
  4. Paxos Made Code 中文、英文
    7.淺談分布式系統的基本問題:可用性與一致性
    8.知行學社的分布式系統與Paxos算法視頻課程
  5. PaxosLease中文、英文
    10.PaxosLease - 老碼農的專欄
    11.Keyspace中的paxos - 老碼農的專欄
    12.分布式領域基本概念- Lease
    13.分布式系統--Lease機制
  6. libpaxoshttp://libpaxos.sourceforge.nethttps://bitbucket.org/sciascid/libpaxos
    15.Fast Paxos - 老碼農的專欄
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容