——轉自:{老碼農的專欄}算法
Paxos算法的難理解與算法的知名度同樣使人敬仰,從我我的的經歷而言,難理解的緣由並非該算法高深到你們智商不夠,而在於Lamport在表達該算法時過於晦澀且缺少一個完整的應用場景。若是大師能換種思路表達該算法,你們可能會更容易接受:數據庫
Lamport首先提出算法的起源,在沒有任何輔助場景下,已經讓不少人陷於泥潭,在滿腦子疑問的前提下,根本沒法繼續接觸算法的具體內容,更無從體會算法的精華。本文將換種表達方法對Paxos算法進行從新描述。promise
咱們全部的描述都假設讀者已經熟讀了Lamport的paxos-simple一文,所以對各類概念再也不解釋。網絡
除了Lamport的幾篇論文,對Paxos算法描述比較簡潔的中文文章是:http://zh.wikipedia.org/zh-cn/Paxos%E7%AE%97%E6%B3%95,該文翻譯的比較到位,但在關鍵細節上仍是存在一些歧義和一些對原文不正確的理解,可能會致使讀者對Paxos算法更迷茫,但閱讀該文能夠快速地對Paxos算法有個大概的瞭解。less
1.應用場景異步
(1)分佈式中的一致性分佈式
Paxos算法主要是解決一致性問題,關於「一致性」,在不一樣的場景有不一樣的解釋:spa
(2)MQ.net
假如全部系統的Log信息都寫入一個MQ Server,而後經過MQ把每條Log指令發異步送到多個Log Server寫入文件(寫入多個Log Server的緣由是對Log文件作備份以防數據丟失),則全部Log Server上的數據確定是一致的(Log內容及順序徹底相同),由於MQ自己就有排序功能,只要進了Q數據也就有了序,至關於編了全局惟一的號,不管把這些數據寫入多少個文件,只要按編號,各文件的內容一定是一致的,但一個MQ Server顯然是一個單點,若是宕機,會影響整個系統的可用性。線程
(3)多MQ
要解決MQ單點問題,首選方案是採用多個MQ Server,即便用一個MQ Cluster,客戶端能夠訪問任意MQ Server,不一樣的客戶端可能訪問不一樣MQ Server,不一樣MQ Server上的數據內容、順序可能不一致,若是不解決這個問題,每一個MQ Server寫入Log Server的內容就不一致,這顯然不是咱們指望的結果。
(4)NoSQL中的數據更新
通常的NoSQL都會經過數據複製的形式保證其可用性,但客戶端對多數據進行操做時,可能會有不少對同一數據的操做發送的某一臺或幾臺Server,有可能執行:Insert、Update A、Update B....Update N,就一次Insert連續屢次Update,最終複製Server上也必須執行這一的更新操做,若是由於線程池、網絡、Server資源等緣由致使各複製Server接收到的更新順序不一致,這樣的複製數據就失去了意義,若是在金融領域甚至會形成嚴重的後果。
上面這些不一致問題性正是Paxos算法要解決的,固然這些問題也不是隻有Paxos能解決,在沒有Paxos以前這些問題也獲得瞭解決,好比經過使用雙Master模式的MQ解決MQ單點問題;經過使用Master Server解決NoSQL的複製問題,但這些解決方法都存在一些缺陷,要麼難水平擴展,要麼影響可用性。固然除了Paxos算法還有其餘一些算法也試圖解決這類問題,好比:Viewstamped Replication算法。
上面描述的這些場景的共性是但願多Server之間狀態一致,也就是一致性,再看中文Wiki開篇提到的:
在一個分佈式數據庫系統中,若是各節點的初始狀態一致,每一個節點都執行相同的操做序列,那麼他們最後能獲得一個一致的狀態。爲保證每一個節點執行相同的命令序列,須要在每一條指令上執行一個「一致性算法」以保證每一個節點看到的指令一致
你們或許會對該描述有更深的理解。
2.Paxos如何解決這類問題
Paxos對這類問題的解決就是試圖對各Server上的狀態進行全局編號,若是能編號成功,那麼全部操做都按照編號順序執行,一致性就不言而喻。當Cluster中的Server都接收了一些數據,如何進行編號?就是表決,讓全部的Server進行表決,看哪一個Server上的哪一個數據應該排第一,哪一個排第二...,只要多數Server贊成某個數據該排第幾,那就排第幾。
很顯然,爲了給每一個數據惟一編號,每次表決只能產生一個數據,不然表決就沒有任何意義。Paxos的算法的全部精力都放在如何在一次表決只產生一個數據。再進一步,咱們稱表決的數據叫Value,Paxos算法的核心和精華就是確保每次表決只產生一個Value。
3.Paxos算法
咱們對原文的概念加以補充:
也就是說,Acceptor對proposer有兩個動做:promise和accept
下面的解釋也主要圍繞着」Only a single value is chosen,「,再看下條件P1,
P1:An acceptor must accept the first proposal that it receives.
乍一看,這個條件是顯然的,由於以前沒有任何value,acceptor理所固然地應該accept第一個proposal,但仔細想一想,感受P1這個條件很不嚴格,究竟是一個對問題的簡單描述仍是一個數學上嚴格的必要條件?這些疑問歸結爲2個問題:
(1)這個條件本質上在保證什麼?
(2)第二個proposal怎麼辦?
在後續的算法中看到一個Acceptor是否批准一個Value與它是不是第一個沒有任何關係,而與這個Proposal的編號有關。那豈不說明P1沒有獲得保證?開始我也百思不得其解,後來通過跟朋友交流發現,P1中的"accept"實際上是指acceptor對proposer的"promise",就是語言描述跟算法的步驟描述之間存在歧義,所以我認爲對算法問題仍是應該採用數學語法而非文字語言。
因此,P1是強調了第一個proposal要被promise,但第二個還未提到,這也是疑問之一。
也很顯然的是,單靠P1是沒法保證Paxos算法的,因可能沒法造成多數派,那接下來的討論應該是考慮如何彌補P1的缺點,使其能夠保證Paxos算法,就是咱們但願將來的條件應該說明:
因而約束P2出現了:
P2:If a proposal with value v is chosen, then every higher-numbered proposal that is chosen has value v.
P2的出現讓人大跌眼鏡,P2並沒沿着P1的路向下走,也沒有解決P1的上述2個不完備,而是從另外一個側面討論如何保證只能選出一個Value。P1討論的是該如何選擇,P2討論的是一旦被選出來,以後的選擇應該不變,就是P1還在討論選的問題,P2已經選出來了,中間有個斷層,怎麼選的沒有討論。
其實從後面Lamport不斷對P2加強能夠看出,P2裏面蘊含着P1(經過proposal編號,第一次以前沒有編號,因此選擇),P2才真正給出了怎麼選擇的具體過程,從過後分析看,P1給出了第一個該怎麼選,P2給出了全部的該怎麼選,條件有點重複。因此,把P1和P2看做是兩個獨立條件的作法是不許確的,於是中文wiki中提到「若是 P1 和 P2 都可以保證,那麼約束2就可以保證」,對細微理解有必定的影響。
也不是說P1就沒有用,反過來看,P2是個未知問題,而P1是這個未知問題的已知部分,從契約的角度來看,P1就是個不變式,任何對P2的加強都不能過了頭以致於沒法知足P1這個不變式,也就是說,P1是P2加強的底線。
那還有沒有其餘的不變式須要遵照?是否在對P2加強的過程當中已破壞了這些未知的不變式?這些高難度的問題牽扯到Paxos算法正確性,要看MIT的嚴格的數學證實,已超出了本文。
另外,中文Wiki對P2的描述是:「P2:一旦一個 value 被批准(chosen),那麼以後批准(chosen)的 value 必須和這個 value 同樣。」,原文采用higher-numbered更能描述將來對proposal進行編號這個事實,而中文采用「以後」,已經徹底失去這個意義。
咱們暫時按下P1不表,近距離觀察一下P2,爲了保證每次選出一個value,P2規定在一個Value已經被選出的狀況下,若是還有其餘的proposer提交value,那以後批准的value應該跟前一個一致,就是在事實上已經選定一個value時,以後的proposer不能提交不一樣的value把以前的結果打亂。這是一個泛泛的描述,但若是這個描述能獲得實現,paxos算法就能獲得保證,所以P2也稱"safety property"。
接下來的討論都時基於「If a proposal with value v is chosen」,如何保證「then every higher-numbered proposal that is chosen has value v」,具體怎麼作到「a proposal with value v is chosen"暫且不談。
P2更可能是從思想層面上提出來該如何解決這個問題,但具體的落實工做須要不少細化的步驟,Lamport是經過逐步加強條件的方式進行落實P2,主要從下面幾個方面進行:
Lamport爲何能把過程劃分的如此清楚已經不得而知,但從Lamport發表的文章來看,他對分佈式有很深的造詣,也持續了很長的時間,能有如此的結果,與他對分佈式的基礎與背後的巨大努力有很大關係。但對咱們而言,不知過程只知個結果,總感受知其然不知其因此然。
咱們沿着上面的思路繼續:
P2a:If a proposal with value v is chosen, then every higher-numbered proposal accepted by any acceptor has value v.
這個條件是在限制acceptor,很顯然,若是P2a獲得了知足,知足P2是確定的,但P2a的加強破壞了P1不變式的底線,具體參考原文,因此P2a自己沒啥意義,轉而從proposer端進行加強。
P2b:If a proposal with value v is chosen, then every higher-numbered proposal issued by any proposer has value v.
這個條件是在限制proposer,若是能限制住proposer,對acceptor的限制固然能被知足的。同時,由於限制proposer必須提交value v,也就順便保證了P1(第一個確定是value v)
但P2b是難以實現的,難實現的緣由是多個proposer能夠提交任意value的proposal,沒法限制proposer不能提交某個value,所以須要尋找P2b的等價條件:
P2c:For any v and n, if a proposal with value v and number n is issued, then there is a set S consisting of a majority of acceptors such that either (a) no acceptor in S has accepted any proposal numbered less than n, or (b) v is the value of the highest-numbered proposal among all proposals numbered less than n accepted by the acceptors in S.
根據原文,P2c裏面蘊含了P2b,但由P2c推導P2b是最難理解的部分。
首先要清楚P2c要作什麼,由於P2b很難直接實現,P2c要作的就是解決P2b的問題,就是解決「若是value v被選擇了,更高編號的提案已經具備value v」,也就是說:
就是要證實若是C成立,那麼結果R成立,而原文的表達是「若是R成立,那麼存在一個條件R」,容易讓人搞混因果關係,再次感嘆若是使用數學符號表達這樣的歧義確定會減小不少。
P2c解決問題的思路是:不是直接嘗試去知足P2b,而是尋找能知足P2b的一個充分條件,若是能知足這個充分條件,那P2b的知足是顯然的。還要強調一點的是proposer能夠提交任意的value,你怎麼能限制我提交的必須是value v呢?其實原文中的「For any v and n, if a proposal with value v and number n is issued」是指「若是一個編號爲n的proposal提交value v,而且value v能被acceptor所接受」,要想被接受就不能隨便提交一個value,就必須是一個受限制的value,這裏討論的前提是value v是要被接受的。而後咱們再看下,是否知足了條件C,結果R就成立。
(a) no acceptor in S has accepted any proposal numbered less than n
若是這個條件成立,那麼n是S中第一個proposal,根據P1,必須接受,因此結果R成立
(b) v is the value of the highest-numbered proposal among all proposals numbered less than n accepted by the acceptors in S
這個證實先假設編號爲n的proposal具備value X被選擇,確定存在一個集合C,其中的每一個acceptor都接受了value X,而集合S中的每一個Acceptor都接受了value v,由於S、C都是多數派,因此存在一個公共成員u,既接受了X,又接受了v,爲了保證選擇的惟一性,必須X=v.
你們可能會發覺該證實有點不太嚴格,「小於n的最大編號」與n之間還有不少proposal,那些proposal也有一些value,那些value會不會不是v?
這個就會用到原文中的數學概括法,就是任意的編號m的proposal具備了value v,那麼n=m+1是,根據上面也是具備value v的,那麼向後遞推,任意的n >m都具備value v。中文wiki中的那個概括證實不須要對m...n-1正推,而對n反證,經過數學概括正推徹底能夠得出最終結果。
也就是說,P2c是P2b的一個增強,知足P2c就能知足P2b。
咱們再近距離觀察下P2c,發現只要在proposer提交提案前,諮詢一下acceptor,看他們的最高編號是啥,他們是否選擇了某個value v,再根據acceptor的回答進行選擇新的編號、value提交,就能夠知足P2c。經過編號,能夠把(a)和(b)兩個條件統一在一塊兒。
其實P2c要表達的思想很是簡單:若是前面有value v選出了,那之後就提交這個value v;不然proposer決定提交哪一個value,具體作法就是事前諮詢,事中決定,過後提交,也就是說能夠經過消息傳遞模型實現。Lamport經過條件、集合、概括證實等形式表達該問題,而沒提這樣作的目的,會致使理解很困難。你們可能會比較疑惑,難道自始至終只能選出一個value?其實這裏的選出,是指一次選舉,而不是整個選舉週期,能夠屢次運行paxos,每次都只選出一個value。
知足P2c從側面也反映出要想提交一個正確的value v,要對proposer、acceptor同時進行限制,僅限制一方問題是沒法解決的。
再回顧下條件之間的遞推關係P2c=>P2b=>P2a=>P2,就是說P2c最終保證了P2,也就是解決了如何作到一個value v被選擇以後,被選擇的編號更大的proposal都具備value v,P2c不只保證P2的結果,更提出了「如何選」的問題,就是上面分階段進行,這就填補了P1與P2之間缺乏如何選的斷層,還有P1的2個不完備問題從直觀上感受會獲得解決,具體的要看算法過程章節。
P1的不完備問題:
P2c也順便解決了P1的不完備問題,由於proposer提交的value是受acceptor限制的,就不會在一次選舉中提交兩個不一樣的value,即便能提交也會由於proposal編號問題有一個會被拒絕,從而能保證能造成多數派。
另外一個關於第二個該怎麼選的不完備問題,也是顯然的了。
再次證實了,P2裏面蘊含了P1,P1只是未知問題P2的不變式。