basic paxos是我見過最難懂的算法,我最近一個月都在研究這個東西,自認有一些粗淺的心得,在這裏寫一下我對它的理解算法
爲了下降理解難度,本文使用了大量的比喻,可能詞不達意,見諒微信
basic paxos只爲了解決一個問題:一個分佈式系統如何就某個值(決議)達成一致。網絡
先給出Wiki上對paxos的流程說明:架構
basic paxos分爲兩個階段:分佈式
prepare 階段:spa
1a) proposer選擇一個提案編號n並將prepare請求發送給acceptors中的一個多數派;get
1b) acceptor收到prepare消息後,若是提案的編號大於它已經回覆的全部prepare消息,則acceptor將本身上次接受的提案回覆給proposer,並承諾再也不回覆小於n的提案;原理
accept 階段:請求
2a) 當一個proposer收到了多數acceptors對prepare的回覆後,就進入批准階段。它要向回覆prepare請求的acceptors發送accept請求,包括編號n和根據P2c決定的value(若是根據P2c沒有已經接受的value,那麼它能夠自由決定value)。qq
2b) 在不違背本身向其餘proposer的承諾的前提下,acceptor收到accept請求後即接受這個請求。
p2c:若是一個編號爲n的提案具備value v,那麼存在一個多數派,要麼他們中全部人都沒有接受(accept)編號小於n的任何提案,要麼他們已經接受(accept)的全部編號小於n的提案中編號最大的那個提案具備value v。
固然,上面說的簡直不像是人話。下面我會嘗試用更容易理解的方式來描述這個算法。
在拍賣行裏拍賣商品時,須要對某個商品競價。
咱們使用basic paxos來限制競價者(proposer)與記帳員(acceptor),但願能在有限輪競價以後,肯定某個商品的歸屬。
前提
1. 記帳員有一張紙,一隻鉛筆,一隻鋼筆和一塊橡皮。鉛筆寫下的字跡能夠被抹掉,鋼筆寫下的字跡不能被抹掉。
2. 競價員能夠給本身更名
3. 有一種特殊的機制,可讓競價者每次的報價都不相同並且遞增
競價過程分爲兩個階段:
準備階段:
1a) 競價者選擇報價n,並將報價n發給超過一半的記帳員
1b) 記帳員收到競價者的報價n以後
if(發現這個報價大於他以前收到過的全部報價) {
if(記帳員已經用鋼筆寫下其餘競價者的報價) {
記帳員將以前用鋼筆寫下的報價和競價者的名字返回
} else {
if(記帳員已經用鉛筆寫下其餘競價者的報價) {
記帳員用橡皮抹去上一次用鉛筆寫下的報價
}
用鉛筆寫下報價n
}
} else {
忽略
}
確認階段:
2a) 競價者收到了大多數記帳員的回覆後,競價者會查看收到的全部回覆。
若是記帳員的回覆中帶有其餘競價者的名字以及他的報價,那麼競價者會選擇其中報價最高的那個回覆,而後將本身的名字改爲這個回覆中帶有的名字。
競價者會向這些記帳員發起確認請求,確認請求中含有本身的報價n和本身的名字(名字可能在上一行中被更新)
2b) 記帳員收到確認請求以後
if(紙上只有鉛筆寫的報價n && 紙上用鉛筆寫下的報價n == 確認請求裏的n) {
記帳員確認這個請求,用鋼筆將確認請求中競價者的名字和報價n寫在紙上
}
補充:若是競價者沒有收到多數派的返回,會提升本身的報價(不與其餘競價者的競價重複)而後從新嘗試競價
前提:咱們有p1p2兩個競價者,和a1a2a3三個記帳員
場景1
a. p1提出競價請求:(1)
b. a1a2a3所有收到,都用鉛筆在紙上記下(1),並回復p1
c. p1收到a1a2a3的回覆,而後向a1a2a3發起確認請求(1,p1)
d. a1a2a3確認,都用鋼筆將(1,p1)寫在紙上
總結
這是一次正常狀況下的請求,a1a2a3最終都記錄了相同的值。
實際上,在這個場景裏,paxos已經退化成了兩階段提交協議。
場景2
a. p1提出競價請求:(1)
b. a1a2收到,都用鉛筆在紙上記下(1),並回復p1,a3網絡中斷沒有收到請求
c. p1收到a1a2的回覆,而後向a1a2發起確認請求(1,p1)
d. a1a2確認,用鋼筆將(1,p1)寫在紙上
總結
雖然有一臺機失效,可是依然保證了多數派寫入數據的一致性。
場景3
a. p1提出競價請求:(1)
b. a1a2a3所有收到,都用鉛筆在紙上記下(1),並回復p1
c. p2提出競價請求:(2)
d. a1a2a3所有收到,因爲p2開價更高,因而放棄p1的競價請求,都用鉛筆在紙上記下(2),並回復p2
e. p1收到步驟b中a1a2a3的回覆,向a1a2a3發起確認請求(1,p1)
f. 因爲a1a2a3的紙上記錄的價格都是2,所以不會理睬p1的確認請求
g. p2收到步驟d中a1a2a3的回覆,向a1a2a3發起確認請求(2,p2)
h. a1a2a3確認,用鋼筆將(2,p2)寫在紙上
總結
雖然有兩次競價請求,可是最終只對其中一次競價請求作出了迴應
場景4
a. p1提出競價請求(1)
b. a1a2收到,都用鉛筆在紙上記下(1),並回復p1。而a3沒有收到
c. p2提出競價請求:(2)
d. a2a3收到,a3直接用鉛筆在紙上寫下(2),a2已經在紙上用鉛筆記下(1),可是因爲p2開價更高,因而放棄p1的競價請求,用鉛筆在紙上記下(2),並回復p2
e. p1收到步驟b中的回覆,向a1a2發起確認請求(1,p1)
f. a1先收到確認請求,用鋼筆在紙上記下(1,p1)。a2後收到確認請求,因爲a2紙上寫的是(2),所以不作反應
g. p1未能達成多數派確認
h. p2收到步驟d中的回覆,向a2a3發起確認請求(2,p2)
i. a2a3收到確認請求,用鋼筆在紙上記下(2,p2)
j. p2達成多數派確認
總結
兩次時序上有交叉的競價請求,致使a1a2a3的最終結果不徹底一致,可是a2a3依然達成了多數派的一致性。
若是想要得到最終確認後的結果,不能只作單點讀取(若是讀到a1就不對了),須要作一次多數派讀取才行。
場景5
a. p1提出競價請求(1)
b. a1a2a3所有收到,都用鉛筆在紙上記下(1),並回復p1
c. p2提出競價請求:(2)
d. a1a2a3所有收到,因爲p2開價更高,因而放棄p1的競價請求,都用鉛筆在紙上記下(2),並回復p2
e. p1收到步驟b中a1a2a3的回覆,向a1a2a3發起確認請求(1,p1)
f. 因爲a1a2a3的紙上記錄的價格都是2,所以不會理睬p1的確認請求
g. p1提升價格,發起競價請求(3)
h. a1a2a3所有收到,因爲p1此次開價更高,因而放棄p2的競價請求,都用鉛筆在紙上記下(3),並回復p1
i. p2收到步驟d中a1a2a3的回覆,向a1a2a3發起確認請求(2,p2)
j. 因爲a1a2a3的紙上記錄的價格都是3,所以不會理睬p2的確認請求
k. p2提升價格,發起競價請求(4,p2)
。。。
總結
p1和p2不斷髮起時序上交叉的競價請求,致使競價請求不斷被互相覆蓋
沒法造成統一的競價結果
這個就是所謂的活鎖(live lock)
場景6
a. p1提出競價請求:(1)
b. a1a2收到,都用鉛筆在紙上記下(1),並回復p1,a3沒有收到請求
c. p1收到a1a2的回覆,而後向a1a2發起確認請求(1, p1)
d. a1a2確認,用鋼筆將(1,p1)寫在紙上
e. p2提出競價請求(2)
f. a2a3收到,a3直接將(2)用鉛筆寫在紙上,a2的紙上已經用鋼筆寫下了(1,p1),所以將此信息返回給p2
g. p2收到a2和a3的回覆,發現a2的紙上已經用鋼筆寫下了(1,p1),所以p2將本身的名字更名爲p1,而後向a2a3發起確認請求(2,p1)
h. a3紙上用鉛筆寫下了(2),與收到的確認請求裏的價格相等,所以a3將確認請求(2,p1)用鋼筆寫在紙上
i. p1在a1a2a3上達成所有確認
總結
雖然p1只在a1和a2上完成多數派確認,可是後來的p2會將這個確認傳遞給其餘的記帳員