Paxos是Lamport大神在1990年提出的,用來解決分佈式系統一致性問題的算法。算法
分佈式系統的一致性關注兩個問題promise
1. 如何就某個決議達成一致性能優化
2. 如何在決議過程結束後保證能最終達成一致微信
例如,在對某個變量達成一致的過程當中,會有多個關於這個變量的值的提議。一致性協議須要保證僅有一個被提議值被最終選擇,且未選擇這個值的節點可以學習到這個值,使集羣最終關於這個值取得一致。異步
協議過程並不複雜,包括三類角色:Proposer(協議發起者)、Acceptor(協議接收者)、Learner(學習者)。具體流程以下分佈式
1. Proposer廣播prepare消息給Acceptor,包含提議序號n。若是Acceptor收到的prepare請求的n值比以前接收到的prepare請求的n值都大的話,回覆promise消息表示不會再接受任何小於n的請求且帶上以前accept的提議中編號小於n的最大的提議,不然不予理會。性能
2. Proposer接收到超過半數的Acceptor關於prepare消息(n)的承諾後,若是沒有發現有一個Accepter接受過一個值,那麼就向全部的Acceptor發送本身提議的值和序號n,不然,從全部接受過的值中選擇一個提議編號最大的做爲提議的值,提議編號仍爲n。學習
3. Acceptor接受到提議後,若是該提議編號不違反本身作過的承諾的話,則接受該提議。Learner根據Acceptor的狀態學習最終被肯定的值優化
注意:若是Proposer發出prepare(n)請求後,獲得多數派的應答,而後能夠再隨便選擇一個多數派廣播accept請求,不必定要將accept請求發給有應答的Acceptor。ui
協議保證多數派達成一致後,不管採用學習的方法仍是重複前兩步流程,最終都能就某個值達成一致。
Paxos流程並不複雜,可是證實過程比較複雜。Lamport爲了讓算法更容易被理解,在2001年寫了Paxos Made Simple,這篇論文沒有一個數學公式,採用邏輯推演的方法從新描述了算法的流程,但仍是沒能顯著下降算法理解的困難度。加之Paxos算法是純理論的推導,工業實踐過程當中每每會經歷較大的改動,谷歌Chubby實現了基於Paxos的一致性算法,雖然做者確定了Paxos在一致性算法領域的地位,可是也認可工業落地後的Paxos算法和原始的Paxos算法差異很大。
國內開源的Paxos工業級別實現是微信的PhxPaxos類庫。
具體實現設計:
Paxos是一個在異步通訊環境中,集羣中多節點存活的條件下可以保證寫入一致的協議。
Paxos只須要和集羣中的多數accepter交互,便可完成一個值的肯定,一旦這個值被選定,不管proposer再發起任何值的寫入,數據都不會再發生改變。
現有的大部分存儲系統都經過AppendLog的形式肯定一個操做序列,當須要恢復一個存儲時能夠經過這個操做序列來恢復,而這個操做序列在肯定以後就永遠不會被修改。
他們將Proposer、各個Acceptor、所服務的Data共同構成一個大集合,這個集合所運行的paxos算法最終目標是肯定一個值。咱們稱這個集合爲一個paxos實例。
實例只能肯定一個單獨的值,如何完成多個實例的有序添加?
給每一個實例生成一個全局只增不減的編號ID,每一個機器的多個實例都是一個連續遞增編號的有序系列,而基於Paxos協議的保證,同一個編號的實例在多一個機器上的值都是一致的,那麼三臺都得到了一個有序的多值存儲。
然而因爲可能出現宕機、消息丟失的狀況,如何解決實例編號增加不一樣步的問題?
Learner詢問其餘機器相同編號的實例,若是這個實例已經被銷燬,則說明這個實例的值已經被肯定,直接將這個值寫入當前實例中而後自增編號跳到下一個實例,如此反覆,直到當前實例編號增加到和其它機器一致。
那麼Paxos如何應用?
可重放的編輯日誌和狀態機結合
Paxos的每一個實例,就是狀態轉移的輸入,因爲每臺機器的實例編號都是有序增加的,而每一個實例肯定的值是同樣的,那麼能夠保證各臺機器的狀態輸入是徹底一致的。根據狀態機的理論,輸入一致,那麼引出的最終狀態也是一致的。
一個Paxos工程實踐的大體流程
客戶端向Proposer發起請求,Proposer與實例編號相同的Acceptor協同工做肯定一個值,以後將這個值做爲狀態機的輸入,產生狀態轉移,最終將狀態轉移結果返回給客戶端。
實現中的性能優化:
嚴格落盤
Paxos協議的運做過程須要作出不少保證,即保證了在相同的條件下必定會作出相同的處理。磁盤是它記錄下這些保證條目的介質。通常使用fsync來解決問題,也就是在每次進行寫盤時都要附加一個fsync進行保證。
爲保證Paxos的寫盤性能,必需要儘量的減小Paxos算法所須要的寫盤次數。理論上Paxos一次交互須要兩次RTT,3次硬盤操做。PhxPaxos庫將其減至一次RTT和一次硬盤操做,大大提升了Paxos協議的性能。
若是出現拜占庭問題的話,工程上就須要一系列的措施檢測出這些拜占庭錯誤,而後選擇性的進行數據回滾或直接丟棄。
一個Leader
多個Proposer寫入是被容許的,只不過愈來愈多的Proposer進行同時寫入,衝突的劇烈程度加大,雖然不會妨礙最終肯定一個值,但在性能上是比較差的。
一個Leader的引入不是爲了解決一致性問題,而是爲了解決性能問題。經過簡單的心跳以及租約就能夠作到。
狀態機記錄最大的實例編號
在每次啓動時,將狀態機告訴Paxos最大的實例編號x與Paxos發現本身最大的已肯定的實例編號y進行對比,若是有x<y的chosen value,咱們將這些value逐一輸入到狀態機,那麼狀態機的狀態就會更新到y了,這個稱爲啓動重放。
參考文章:
微信PaxosStore:深刻淺出Paxos算法協議 做者:鄭建軍
微信開源:生產級paxos類庫PhxPaxos實現原理介紹 做者:lunncui