在分佈式系統中如何實現跨進程通訊,這是一個經典問題。主要的解決方案包含了兩種:web
本篇不記錄關於共享內存的方式,將從消息傳遞方式引出paxos算法。在基於消息傳遞通訊模型的分佈式系統中,不可避免的會發生進程變慢、被殺死或者重啓,消息可能會發生延遲、重複、丟失等問題。在一個典型的場景中,一個分佈式數據庫系統,若是各個節點初始狀態一致,每一個節點都進行相同的操做,那麼他們最後是一個一致的狀態。爲了保證每個節點都保證一致的狀態,那麼就須要在每一條指令上都執行一個共識算法
以保證每個節點看到的指令(插入、更新、刪除)都是一致的。一個通用的共識算法能夠應用在許多場景中,是分佈式計算中的重要問題。所以從20世紀80年代起對於共識算法的研究就沒有中止過。算法
1982年一位叫Lamport的大神與另外兩位做者發表了一篇論文The Byzantine Generals Problem,文中已較爲晦澀的方式闡述了Paxos
算法,由此打開了計算機在分佈式一致性方面的大門,這也是目前公認的解決分佈式一致性問題的有效辦法,該論文較爲難懂,如若想更好的理解還請參看Paxos Made Simple數據庫
若想了解一致性算法,那麼先要明確幾個實際需求。假設有一組能夠提出提案的進程,那麼對於一個一致性算法來講須要保證如下幾點:異步
帶着這幾個需求再來深刻了解Paxos算法。分佈式
在Paxos中共有三種角色參與,用 Proposer、Acceptor、Learner 表示(固然,容許身兼多職),Proposer負責提出提案,提案包括了提案編號和提案內容(好比:提案001-將稅率提高10%),Acceptor能夠接收提案,若提案被多數的Acceptor接受,那麼將會被提交批准(chosen),Learner只可以從Acceptor那裏學習被批准的提案。學習
上邊的說法可能很差理解,能夠將其理解爲表明與羣衆的關係,表明能夠是Proposer同時也是Acceptor,他們在會議上提出提案,由其餘的表明一同決定是否統一該提案,若是多數贊成,那麼該提案也就意味着經過,羣衆再從各個表明那裏學習提案精神。明確了角色關係,再回頭看以前的問題:優化
批准value的過程當中,首先Proposer將value發送給Acceptor,以後Acceptor對value進行接受。爲了知足只批准一個value的約束,要求經多數派接受的提案value成爲決議
。這是由於不管是按照人數仍是按照權重劃分,兩組多數派至少有一個公共的Acceptor,若是每一個Acceptor只能接受一個value,約束2就能保證。.net
因而產生了一個顯而易見的新約束:code
P1:一個Acceptor必須接受(accept)第一次收到的提案。
注意 P1 是不完備的。若是剛好一半Acceptor接受的提案具備valueA,另外一半接受的提案具備valueB,那麼就沒法造成多數派,沒法批准任何一個value。進程
約束2並不要求只批准一個提案,暗示可能存在多個提案。只要提案的value是同樣的,批准多個提案不違背約束2。因而能夠產生約束 P2:
P2:一旦一個具備valuev 的提案被批准(chosen),那麼以後批准(chosen)的提案必須具備valuev。
注:經過某種方法能夠爲每一個提案分配一個編號,在提案之間創建一個全序關係,所謂「以後」都是指全部編號更大的提案。
若是 P1 和 P2 都可以保證,那麼約束2就可以保證。
批准一個value意味着多個Acceptor接受(accept)了該value。所以,能夠對 P2 進行增強:
P2a:一旦一個具備valuev 的提案被批准(chosen),那麼以後任何Acceptor再次接受(accept)的提案必須具備valuev。
因爲通訊是異步的,P2a 和 P1 會發生衝突。若是一個value被批准後,一個Proposer和一個Acceptor從休眠中甦醒,前者提出一個具備新的value的提案。根據 P1,後者應當接受,根據 P2a,則不該當接受,這種場景下 P2a 和 P1 有矛盾。因而須要換個思路,轉而對Proposer的行爲進行約束:
P2b:一旦一個具備valuev 的提案被批准(chosen),那麼之後任何Proposer提出的提案必須具備valuev。
因爲Acceptor能接受的提案都必須由Proposer提出,因此 P2b 蘊涵了 P2a,是一個更強的約束。
可是根據 P2b 難以提出實現手段。所以須要進一步增強 P2b。
假設一個編號爲 m 的valuev 已經得到批准(chosen),來看看在什麼狀況下對任何編號爲 n(n>m)的提案都含有valuev。由於 m 已經得到批准(chosen),顯然存在一個Acceptor的多數派 C,他們都接受(accept)了v。考慮到任何多數派都和 C 具備至少一個公共成員,能夠找到一個蘊涵 P2b 的約束 P2c:
P2c:若是一個編號爲n的提案具備valuev,該提案被批准(chosen),那麼存在一個多數派,要麼他們中全部人都沒有接受(accept)編號小於n的任何提案,要麼他們已經接受(accept)的全部編號小於n的提案中編號最大的那個提案具備valuev
要知足P2c的約束,Proposer提出一個提案前,首先要和足以造成多數派的Acceptor進行通訊,得到他們進行的最近一次接受(accept)的提案(prepare過程),以後根據回收的信息決定此次提案的value,造成提案開始投票。當得到多數Acceptor接受(accept)後,提案得到批准(chosen),由acceptor將這個消息告知learner。這個簡略的過程通過進一步細化後就造成了Paxos算法。
在一個paxos實例中,每一個提案須要有不一樣的編號,且編號間要存在全序關係。能夠用多種方法實現這一點,例如將序數和Proposer的名字拼接起來。如何作到這一點不在Paxos算法討論的範圍以內。
若是一個沒有chosen過任何Proposer提案的acceptor在prepare過程當中回答了一個Proposer針對提案n的問題,可是在開始對n進行投票前,又接受(accept)了編號小於n的另外一個提案(例如n-1),若是n-1和n具備不一樣的value,這個投票就會違背P2c。所以在prepare過程當中,acceptor進行的回答同時也應包含承諾:不會再接受(accept)編號小於n的提案。這是對P1的增強:
P1a:當且僅當acceptor沒有迴應過編號大於n的prepare請求時,acceptor接受(accept)編號爲n的提案。
經過一個決議分爲兩個階段:
prepare階段:
舉例來講,當前Acceptor已經回覆了編號爲一、二、三、四、5提案,那麼該Acceptor在接收到編號爲6的提案時,將會回覆編號5,而且承諾不會再接收編號小於6的提案。
批准階段:
在實際運行中,每個Proposer都有可能產生多個提案,但只要系統按照當前算法運行,那麼就可以保證正確性。若是一個Proposer已經生成了更大的提案編號,那麼刪除編號較小的是一個更好的選擇,因此在Acceptor接收到一個編號爲n的請求,但其發現已經接受了比n更大的編號,那麼它會通知發送編號n提案的Proposer,讓其將這個提案刪除掉。
根據上述過程當一個Proposer發現存在編號更大的提案時將終止提案。這意味着提出一個編號更大的提案會終止以前的提案過程。若是兩個Proposer在這種狀況下都轉而提出一個編號更大的提案,就可能陷入活鎖,也就是二者不停的拿出更大的提案,這違背了算法可持續性的要求。通常活鎖能夠經過隨機睡眠-重試
的方法解決。
不過在這種狀況下的更好的解決方案是選舉出一個leader Proposer,僅容許leader提出提案。這樣一來只要主Proposer和過半數的Acceptor可以進行通訊,那麼提案就可以被批准。
這種狀況下的解決方案是選舉出一個leader,僅容許leader提出提案。可是因爲消息傳遞的不肯定性,可能有多個proposer自認爲本身已經成爲leader。這也就須要提供leader Proposer高可用。
本文經過對分佈式系統的消息傳遞模型分析,進而引伸出Paxos算法,Paxos經過引入過半原則,和基於2PC的機制,進一步優化了2PC和3PC中包含的問題,解決的同步阻塞、腦裂、無限期等待等問題。能夠說Paxos算法是分佈式一致性共識協議中較爲理想的實現。