引言html
《分佈式系統理論基礎 - 一致性、2PC和3PC》一文介紹了一致性、達成一致性須要面臨的各類問題以及2PC、3PC模型,Paxos協議在節點宕機恢復、消息無序或丟失、網絡分化的場景下能保證決議的一致性,是被討論最普遍的一致性協議。git
Paxos協議同時又以其「艱深晦澀」著稱,下面結合 Paxos Made Simple、The Part-Time Parliament 兩篇論文,嘗試經過Paxos推演、學習和了解Paxos協議。github
Basic Paxos數據庫
何爲一致性問題?簡單而言,一致性問題是在節點宕機、消息無序等場景可能出現的狀況下,相互獨立的節點之間如何達成決議的問題,做爲解決一致性問題的協議,Paxos的核心是節點間如何肯定並只肯定一個值(value)。promise
也許你會疑惑只肯定一個值能起什麼做用,在Paxos協議裏肯定並只肯定一個值是肯定多值的基礎,如何肯定多值將在第二部分Multi Paxos中介紹,這部分咱們聚焦在「Paxos如何肯定並只肯定一個值」這一問題上。微信
和2PC相似,Paxos先把節點分紅兩類,發起提議(proposal)的一方爲proposer,參與決議的一方爲acceptor。假如只有一個proposer發起提議,而且節點不宕機、消息不丟包,那麼acceptor作到如下這點就能夠肯定一個值:網絡
P1. 一個acceptor接受它收到的第一項提議
固然上面要求的前提條件有些嚴苛,節點不能宕機、消息不能丟包,還只能由一個proposer發起提議。咱們嘗試放寬條件,假設多個proposer能夠同時發起提議,又怎樣才能作到肯定並只肯定一個值呢?分佈式
首先proposer和acceptor須要知足如下兩個條件:性能
1. proposer發起的每項提議分別用一個ID標識,提議的組成所以變爲(ID, value)學習
2. acceptor能夠接受(accept)不止一項提議,當多數(quorum) acceptor接受一項提議時該提議被肯定(chosen)
(注: 注意以上「接受」和「肯定」的區別)
咱們約定後面發起的提議的ID比前面提議的ID大,並假設能夠有多項提議被肯定,爲作到肯定並只肯定一個值acceptor要作到如下這點:
P2. 若是一項值爲v的提議被肯定,那麼後續只肯定值爲v的提議
(注: 乍看這個條件不太好理解,謹記目標是「肯定並只肯定一個值」)
因爲一項提議被肯定(chosen)前必須先被多數派acceptor接受(accepted),爲實現P2,實質上acceptor須要作到:
P2a. 若是一項值爲v的提議被肯定,那麼acceptor後續只接受值爲v的提議
知足P2a則P2成立 (P2a => P2)。
目前在多個proposer能夠同時發起提議的狀況下,知足P一、P2a即能作到肯定並只肯定一個值。若是再加上節點宕機恢復、消息丟包的考量呢?
假設acceptor c 宕機一段時間後恢復,c 宕機期間其餘acceptor已經肯定了一項值爲v的決議但c 由於宕機並不知曉;c 恢復後若是有proposer立刻發起一項值不是v的提議,因爲條件P1,c 會接受該提議,這與P2a矛盾。爲了不這樣的狀況出現,進一步地咱們對proposer做約束:
P2b. 若是一項值爲v的提議被肯定,那麼proposer後續只發起值爲v的提議
知足P2b則P2a成立 (P2b => P2a => P2)。
P2b約束的是提議被肯定(chosen)後proposer的行爲,咱們更關心提議被肯定前proposer應該怎麼作:
P2c. 對於提議(n,v),acceptor的多數派S中,若是存在acceptor最近一次(即ID值最大)接受的提議的值爲v',那麼要求v = v';不然v可爲任意值
知足P2c則P2b成立 (P2c => P2b => P2a => P2)。
條件P2c是Basic Paxos的核心,光看P2c的描述可能會以爲一頭霧水,咱們經過 The Part-Time Parliament 中的例子加深理解:
假設有A~E 5個acceptor,- 表示acceptor因宕機等緣由缺席當次決議,x 表示acceptor不接受提議,o 表示接受提議;多數派acceptor接受提議後提議被肯定,以上表格對應的決議過程以下:
以上提到的各項約束條件能夠概括爲3點,若是proposer/acceptor知足下面3點,那麼在少數節點宕機、網絡分化隔離的狀況下,在「肯定並只肯定一個值」這件事情上能夠保證一致性(consistency):
(注: 希臘字母ß表示多輪決議的集合,字母B表示一輪決議)
另外爲保證P2c,咱們對acceptor做兩個要求:
1. 記錄曾接受的ID最大的提議,因proposer須要問詢該信息以決定提議值
2. 在迴應提議ID爲n的proposer本身曾接受過ID最大的提議時,acceptor同時保證(promise)再也不接受ID小於n的提議
至此,proposer/acceptor完成一輪決議可概括爲prepare和accept兩個階段。prepare階段proposer發起提議問詢提議值、acceptor迴應問詢並進行promise;accept階段完成決議,圖示以下:
還有一個問題須要考量,假如proposer A發起ID爲n的提議,在提議未完成前proposer B又發起ID爲n+1的提議,在n+1提議未完成前proposer C又發起ID爲n+2的提議…… 如此acceptor不能完成決議、造成活鎖(livelock),雖然這不影響一致性,但咱們通常不想讓這樣的狀況發生。解決的方法是從proposer中選出一個leader,提議統一由leader發起。
最後咱們再引入一個新的角色:learner,learner依附於acceptor,用於習得已肯定的決議。以上決議過程都只要求acceptor多數派參與,而咱們但願儘可能全部acceptor的狀態一致。若是部分acceptor因宕機等緣由未知曉已肯定決議,宕機恢復後可經本機learner採用pull的方式從其餘acceptor習得。
Multi Paxos
經過以上步驟分佈式系統已經能肯定一個值,「只肯定一個值有什麼用?這可解決不了我面臨的問題。」 你心中可能有這樣的疑問。
其實不斷地進行「肯定一個值」的過程、再爲每一個過程編上序號,就能獲得具備全序關係(total order)的系列值,進而能應用在數據庫副本存儲等不少場景。咱們把單次「肯定一個值」的過程稱爲實例(instance),它由proposer/acceptor/learner組成,下圖說明了A/B/C三機上的實例:
不一樣序號的實例之間互相不影響,A/B/C三機輸入相同、過程實質等同於執行相同序列的狀態機(state machine)指令 ,於是將獲得一致的結果。
proposer leader在Multi Paxos中還有助於提高性能,常態下統一由leader發起提議,可節省prepare步驟(leader不用問詢acceptor曾接受過的ID最大的提議、只有leader提議也不須要acceptor進行promise)直至發生leader宕機、從新選主。
小結
以上介紹了Paxos的推演過程、如何在Basic Paxos的基礎上經過狀態機構建Multi Paxos。Paxos協議比較「艱深晦澀」,但多讀幾遍論文通常能理解其內涵,更難的是如何將Paxos真正應用到工程實踐。
微信後臺開發同窗實現並開源了一套基於Paxos協議的多機狀態拷貝類庫PhxPaxos,PhxPaxos用於將單機服務擴展到多機,其通過線上系統驗證並在一致性保證、性能等方面做了不少考量。
--
本文提到的一些概念包括一致性(consistency)、一致性系統模型(system model)、多數派(quorum)、全序關係(total order)等,在如下文章中有介紹 :)
--