Paxos--分散式一致性演算法
相關概念
instance(例項):一次Paxos演算法執行。
proposal(議案):未經批准的決議稱為議案。
value(決議):被最終批准通過的議案中的value,也就是proposal提案對應的值
Proposer(提案者):提出議案
Acceptor(批准者):審批議案
Leaner(學習者):學習決議
minProposal(最小提案值):在一個Paxos Instance內,當前接收的最小提議值,會不斷更新
Paxos選舉的流程
Paxos Instance主要包括兩個階段:準備階段(prepare phase)和提議階段(accept phase)。如下圖所示:
1. 準備階段 prepare
1.獲取一個Proposal ID,也就是n,為了保證Proposal ID遞增,可以採用時間戳+server ID方式生成;
2.提議者向所有節點(提議者)廣播prepare(n)請求;
3.接收者比較n和minProposal,如果n>minProposal,表示有更新的提議,更新最小提案值minProposal=n;否則將(acceptedProposal,acceptedValue)返回,即將acceptor內部儲存的最小提案值返回到接受者,便於接受者根據提案值重新獲取一個大於該提案值的Proposal ID;
if n > minProposal
then minProposal = n;// 有更新的提議;更新最小提案值
else
return (acceptedProposal, acceptedValue);//將acceptor內部儲存的最小提案值返回到提議者,便於提議者根據最小提案值重新獲取一個大於該提案值的Proposal ID;
4.提議者接收到過半數請求(多數派、法定集合)後,如果發現有acceptedValue返回,表示有比當前proposal更新的提議,儲存acceptedValue到本地,然後跳轉到步驟1,生成一個ID值更高的提議;
提議階段 accpetor
5.到這裡表示在當前paxos instance內,沒有優先順序更高的提議,可以進入第二階段,廣播accept(n,value)到所有節點;
6.接收者比較n和minProposal,如果n>=minProposal,則acceptedProposal=minProposal=n,acceptedValue=value,本地持久化後,返回;
否則,返回minProposal,表示在接受者裡有比n更新的提議,需要重新進行提交提議;
7.提議者接收到過半數請求後,如果發現有返回值>n,表示有比n更新的提議,跳轉到步驟1;否則value達成一致。
從上述流程可知,併發情況下,可能會出現第4步或者第7步頻繁重試的情況,導致效能低下,更嚴重者可能導致永遠都無法達成一致的情況,就是所謂的“活鎖”,如下圖所示:
1.S1作為提議者,發起prepare(3.1),並在S1,S2和S3達成多數派;
2.隨後S5作為提議者 ,發起了prepare(3.5),並在S3,S4和S5達成多數派;
3.S1發起accept(3.1,value1),由於S3上提議 3.5>3.1,導致accept請求無法達成多數派,S1嘗試重新生成提議
4.S1發起prepare(4.1),並在S1,S2和S3達成多數派
5.S5發起accpet(3.5,value5),由於S3上提議4.1>3.5,導致accept請求無法達成多數派,S5嘗試重新生成提議
6.S5發起prepare(5.5),並在S3,S4和S5達成多數派,導致後續的S1發起的accept(4.1,value1)失敗……
prepare階段有兩個目的:
1)檢查是否有被批准的值,如果有,就改用批准的值;
2)如果之前的提議還沒有被批准,則阻塞掉他們,從而不讓它們與其自身發生競爭(由提議ID的大小決定)。
Paxos協議對於如何決定變數v的值的流程。
提議者:
詢問:詢問法定集合的程序自身v的值;
預提議:傳送包含自身proposer-id的預提案給法定集合接受者;
提議:傳送的預提案得到一個法定集合接受者的回覆後,如果詢問的結果是法定集合的接受者均未給v賦予值,那麼提議者擁有自由賦值的權利,不然提議者從中選擇一個值賦予給v。假定自由賦予或者選擇的值為c,傳送包含c和proposer-id的提案給接受者。
接受者:
處理詢問:回覆自身v的值處理預議案:如果收到的預提案ppq.proposer-id>自身a-proposer-id,那麼更新自身a-proposer-id=ppq.proposer-id,接受這個預提案,否則拒絕這個預提案。
處理提議:如果收到的提案的pq.proposer-id>=自身a-proposer-id,那麼更新a-proposer-id=pq.proposer-id,接受這個提案,記錄v的值為提案中的值,即v=pq.c。
>無論是提案還是預提案,接受者只接受proposer-id比它自身的a-proposer-id更大的訊息。