分布式一致性之Paxos

Paxos追本溯源

Paxos是分布式專家Leslie Lamport的大作,他在分布式一致性領域做出了很多突出的貢獻。Lamport最初在研究拜占庭將軍問題,從理論上證明了在分布式領域,試圖在異步和不可靠的通道上達成一致的狀態是不可能的。而事實上,這種信道問題可以是不存在的或者說是可以避免的。于是Lamport基于此提出了Paxos,證明在信道可靠并且不要求liveness的情況下是可以達到分布式一致的。下面我們便來看看Paxos到底是什么。

Paxos問題描述

假設有一個進程集合,這些進程都能夠提出自己決議,而且每個進程提出的決議有可能是不同的,在這種情況下Paxos算法要在眾多的決議中給出唯一的選擇。要達到Paxos所說的安全性,需要滿足如下幾個條件:1)只有被提議的值才能被選中;2)最終只有一個唯一值能被選中;3)在最終被決議前,任何參與者都不能獲得決議結果。

試想你在參加一次會議,大家就某個問題確定一個最終方案,一般會怎么做?首先肯定要有人提出方案,參會者聽到方案后經過大腦的處理并分析利弊,于是做出自己的判斷接受或者不接受這個方案。當然其他參會者如果不同意也可以提出自己的方案,最終大家經過討論,一致通過某個方案。這樣一個簡單的決議中,存在著三種角色:提議者、決議者、學習者,在Paxos算法中也同樣對應著這三種角色,分別為proposer, acceptor, learner,當然每個人都可以身兼多個角色,但是為了方便問題的討論Paxos還是把他們區分開來。

Paxos角色關系


下面我們就來看看Paxos算法是如何保證一個提議是最終被選擇的。

Paxos推導過程

當acceptor只有一個的時候問題會變得很簡單,它只要接受收到的proposal就可以,但我們還需要考慮可用性,所以一般都會有多個acceptor。在有多個acceptor的情況下怎樣算通過決議呢,難道真的要所有的acceptor都統一戰線才算成功嗎?這里就要提到多數派(majority)特性,Paxos只要多數派接受了提議這個提議便被接受了,然后learner可以通過主動或者被動的方式獲取投票的結果。Lamport在他的論文Paxos made simple中給出了算法的推導過程,我們現在來看看他是如何推導的。

通常情況下考慮到消息丟失或者發送失敗等情況,我們希望acceptor能夠在proposer只提出了一個proposal的情況下依然能正常工作,很自然的可以給出第一個保證:

P1. acceptor必須接受它收到的第一個proposal。

給出第一個保證的同時也帶來了問題,不同的proposer同時提出了不同的提議,但是由于消息的到達順序不一樣導致不同的acceptor接受了不同的proposal,于是無法形成多數派,也就是說無法給出最終的決議,這就要求acceptor可以變更自己的選擇,proposer不停的提出決議直到acceptor多數派達成一致。

無法形成多數派的情況

為了能最終達到統一的結果,需要給出第二個保證:

P2. 假如提議值v被選中,接下來更大編號的提議被選中,被選中的值也一定是v。

換個視角從proposer的角度去看,于是我們可以通過P2a來滿足P2:

P2a. 假如提議值為v的某個提議被選中,那么被接受的更大編號的提議的值也一定是v。

我們的分布式系統是基于消息傳遞的,并且都是異步的會存在消息都是或者延遲,假設acceptor c由于以上提到的某種原因沒有收到提議。這時一個新的proposer被喚醒并發出更大編號的提議,它的值與之前的提議都不同。回顧之前的保證P1, ?c會接受它收到的第一個提議。這種情況就違背了P2a的保證。

在P2a保證下無法達到一致的情況


怎么辦才能既保證P2a同時又不違背P1呢,我們可以進一步加強條件:

P2b. 假如提議值為v的某個提議被選中,那么proposer提出的更大編號的提議的值都必須是v。

P2b看似合理,但并好實現,我們在這里不試圖去證明P2b的合理性,感興趣的讀者可以參考Lamport的大作Paxos made simple。通過證明過程,更進一步提出下面的保證:

P2c. 對于任意提議,它的編號是n,提議值是v,肯定存在由半數以上acceptor組成的集合S滿足以下兩個條件中任意一個 (1)S中不存在任何批準過編號小于n的提案的acceptor,(2)選取S中所有acceptor批準的編號小于n的提案,其中編號最大的那個提議的值。

滿足P2c,proposer就要知道比n小的最大編號的提議。獲取已經被大多數通過的決議比較容易,預測未來可能被接受的決議卻很困難。避免以上的困難,只要acceptor保證不接受任何編號比n小的提議就夠了,接下來我們來看看這個Paxos算法的過程。

Paxos算法描述

階段一,prepare請求

1. proposer選擇提議編號n,然后向超過半數的acceptor發送編號為n的prepare請求。

2. 如果acceptor收到編號為n的請求,且編號大于已經響應的所有prepare請求的編號,那么它就會將批準過的最大編號的提議反饋給proposer,同時acceptor承諾不會再批準任何編號小于n的提案。

階段二,accept請求

1. 如果proposer收到大多數acceptor的響應,它就會發送一個針對編號n值為v的提議,v就是收到的響應中編號最大的提議的值;如果響應中不包含任何提議,那么它就是任意值。

2. acceptor收到編號為n的提議,如果尚未對編號比n大的prepare請求作出過響應,它就可以通過這個提議。

具體詳細流程如下圖所示:

Paxos算法

值得一提的是acceptor需要持久化minProposal,acceptedProposal和acceptedValue,這樣在宕機恢復的時候能夠保證自己狀態的一致性。

寫在最后

分布式一致性的實現方式可以有千萬種,但是Paxos在保證系統高可用的情況下選擇了一條捷徑,使得分布式系統可以既安全又快速的達成一致,這就是它的偉大之處,也是它的作者Lamport對人類和分布式領域的巨大貢獻。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容