十分鐘理解Paxos演算法
Paxos是什麼?
世界上只有一種分散式一致性協議那就是Paxos,其它的演算法都是Paxos的改進或簡化。
Paxos理解困境
由於理解Paxos比較複雜,使其推廣上比較困難,下面就來嘗試一下用通俗易懂的語言來描述Paxos.
Paxos解決什麼問題?
在一個分散式系統如何就某個值(決議)達成一致,該值可以是任意的二進位制的資料。一旦確定,將不再會被更改。
備註: 典型的應用場景就是Zookeeper的Leader選舉。
Paxos的兩個原則:
安全原則---保證不能做錯的事
1. 只能有一個值被批准,不能出現第二個值把第一個覆蓋的情況
2. 每個節點只能學習到已經被批准的值,不能學習沒有被批准的值
1. 最終會批准某個被提議的值
2. 一個值被批准了,其他伺服器最終會學習到這個值
Paxos的兩個元件
Proposer
提議發起者,處理客戶端請求,將客戶端的請求傳送到叢集中,以便決定這個值是否可以被批准。
Acceptor
提議批准者,負責處理接收到的提議,他們的回覆就是一次投票。會儲存一些狀態來決定是否接收一個值
Paxos一步步理解:
假設每一臺伺服器都是一個提議者 (Proposer),也是一個批准者(Acceptor)。
理解paxos的關鍵在於假設一個時刻只有一臺機器在做,理解了一臺機器演算法原理後,再去證明多臺機器同時做也是可行的。
一個批准者
首先從最簡單的方式開始,假設只有一個批准者,讓它做決定是否批准一個值。
如上圖,提議者分別提議一個值,然後批准者批准一個值作為最終的值。
單點問題
這種簡單的方式存在單點問題,如果唯一的批准者crash了,就沒有辦法知道哪個值被選擇了,就需要等待它重啟,這一條違反了存活原則,剩除的4臺伺服器存活,但已經沒有辦法工作了。
誰被批准
有個潛在問題,批准者無法確定哪個值最終被批准。
多個批准者
為了解決這個問題,就必須要有一個批准者的集合。然後只有其中的多數批准了一個值,這個值才可以確實是被最終被批准的。為了達到目的也需要一些技巧。
批准第一個達到的值
首先規定每個批准者必須批准第一個到達的值。哪個值達到多數批准就是最終批准的值
但是有一個問題,因為沒有值被多數批准,無法批准一個最終的值出來。這就需要批准者批准了一個值之後還要根據某種規則批准不同的值。
批准每個提議的值
接下來規定Acceptor批准每個提議的值,但是這也會帶來一個問題,可能會批准出多個值
如圖,S1發出提議,A,B,C批准A為最終批准的值。E隨後發出提議,C,D,E批准,E又為最終批准的值。此時A,B最終批准A,C,D,E最終批准E,這就違背了我們的一致性原則,最終只有一個值被選擇。
二段提交原則
要解決這個問題,就要E在傳送自己的提議之前,優先檢查有沒有已經被批准的值,如果有應該提議已經被批准的值而放棄自己的值,也就是放棄自己的A改為提議E,這樣最終只有一個值被批准就是E。這個就是經典的二段提交原則。
如圖,A在傳送提議之前,檢查沒有值被批准,因此提議A。但同時在所有Acceptor批准之前,S5也要進行提議,這個時候也檢查出沒有值被批准,所以它也把自己的E作為提議傳送給acceptor。接下來S5的提議優先到達C,D,E,這些Acceptor先批准了E,達到多數所以E最終被批准了。但是隨後A,B,C接收到了A進行批准。所以又出現了批准出多個值的問題。
提議排序
這個問題要解決,就需要一旦Acceptor批准了某個值,其他有衝突的值都應該被拒絕。也就是說B隨後到達的A應該被拒絕,為了做到這一點。需要對Proposer進行排序,將排序在前的賦予高優先順序,Acceptor批准優先順序高的值,拒絕排序在後的值。
為了將提議進行排序,可以為每個提議賦予一個唯一的ID,規定這個ID越大,優先順序越高
在提議者傳送提議之前,就需要生成一個唯一的ID,而且需要比之前使用的或者生成的都要大
提議ID生成演算法
在Google的Chubby論文中給出了這樣一種方法:假設有n個proposer,每個編號為ir(0<=ir<n),proposor編號的任何值s都應該大於它已知的最大值,並且滿足:s %n="ir" =="" data-spm-anchor-id="ata.13261165.0.i24.48164976xSOcwl">s = m*n + ir
proposer已知的最大值來自兩部分:proposer自己對編號自增後的值和接收到acceptor的reject後所得到的值
以3個proposer P1、P2、P3為例,開始m=0,編號分別為0,1,2
1. P1提交的時候發現了P2已經提交,P2編號為1 > P1的0,因此P1重新計算編號:new P1 = 1*3+0 = 4
2. P3以編號2提交,發現小於P1的4,因此P3重新編號:new P3 = 1*3+2 = 5
到此階段,要保證Paxos的兩個原則已經都滿足了,Paxos也就順利的實現了。
二階段提交總結
prepare 階段:
1. Proposer 選擇一個提案編號 n 並將 prepare 請求傳送給 Acceptors 中的一個多數派;
2. Acceptor 收到 prepare 訊息後,如果提案的編號大於它已經回覆的所有 prepare 訊息,則 Acceptor 將自己上次接受的提案回覆給 Proposer,並承諾不再回復小於 n 的提案;
acceptor階段:
1. 當一個 Proposer 收到了多數 Acceptors 對 prepare 的回覆後,就進入批准階段。它要向回覆 prepare 請求的 Acceptors 傳送 accept 請求,包括編號 n 和根據 prepare階段 決定的 value(如果根據 prepare 沒有已經接受的 value,那麼它可以自由決定 value)。
2. 在不違背自己向其他 Proposer 的承諾的前提下,Acceptor 收到 accept 請求後即接受這個請求。
prepare階段有兩個目的,第一檢查是否有被批准的值,如果有,就改用批准的值。第二如果之前的提議還沒有被批准,則阻塞掉他們以便不讓他們和我們發生競爭,當然最終由提議ID的大小決定。整個過程如下圖