paxos算法號稱是"世界上惟一的分佈式一致性算法",其餘任何一致性算法都是它的變體.html
最近在看paxos算法, 看了很多博客, 都感受總結得不夠到位,甚至有理解誤差的地方,卻是在博客的引用文章裏面找到了一篇英文文獻,看完後豁然開朗茅塞頓開.算法
因而把那篇英文原文翻譯了一下, 加深一下理解架構
英文文獻雖是2012年的了, 可是短小精悍,值得一看,原文地址是:分佈式
文章中不全是直譯, 有些地方改爲了我本身的理解, 因此有可能有理解錯的地方, 還望指出.3d
另外在理解的過程當中參考到了如下這篇文章, 也是一篇paxos算法相關的譯文cdn
本文經過一個實例描述了一個叫Paxos的分佈式一致性算法blog
分佈式一致性算法一般是用於讓多個計算機節點就某個單值的修改達成一致, 例如事務的提交commit或回滾rollback, 典型的思想就是二階段提交或三階段提交.事務
算法並不關心這個單值是什麼,只關心最後只有惟一一個值被全部的節點選中, 對該值的修改達成一致
在一個分佈式系統中這很是的難, 由於不一樣機器以前的消息可能會丟失, 或是被無限延遲, 甚至機器自己也會掛掉
Paxos算法能夠保證最終只會有一個值會被選中, 可是不能保證若是集羣中的大多數節點掛掉後,還能選中一個值
Paxos的節點能夠是proposer, acceptor,learner中的任何一種角色.proposer會提議一個它想被採納的值, 通常是經過發送一個包含該提議值的提案給集羣中的每一個acceptor. 而後acceptor會獨立的決定是否接受這個提案--它可能會接收到多個proposer的不一樣提案, 決定好後會把它的決定發給learner. learner的做用是判斷一個值是否已經被接受.在Paxos算法中, 只有一個值被大多數的acceptor選中, 纔算被Paxos算法選中.在實際項目中, 一個節點可能擔任多種角色, 可是在這個例子裏面, 每一種角色都是一個獨立的節點.
圖1 Paxos的基本架構. 幾個proposer向acceptor提交提案. 當一個acceptor接受了一個值後, 它把它的決定發給learner
在標準的Paxos算法中, 一個proposer會發送兩種類型的消息給acceptors: prepare request 和accept request. 在算法的第一階段, proposer會發送一個prepare request給每個acceptor, 這個prepare request包含一個提議值value和一個提案號number.每個proposer的提案號number必須是正數, 單調遞增的,獨一無二的天然數[1].
在下面圖2的例子中, 有兩個proposer, 都在發送prepare request. proposer A的請求([n=2,v=8])比proposer B的請求([n=4,v=5])先到達acceptor X和acceptor Y, 而proposer B的請求先到達acceptor Z
圖2: Paxos. proposer A和B各發送了一個prepare request 給每個accetor. 在這個例子中, proposer A的請求先到達acceptor X和Y, 而proposer B的請求先到達了acceptor Z.
若是一個acceptor接收到了一個prepare request而又沒接收過其餘的提案, 這個acceptor會迴應一個prepare response, 並保證不會接受其餘比當前提案號number更小的提案. 下面圖3展現了每一個acceptor是如何響應它們接收到的prepare request的
圖3: 每一個acceptor都對它接收到的第一個prepare request 進行prepare response.
最終, acceptor Z接收到了proposer A的請求[2], acceptor X和Y收到了proposer B的請求.
若是一個acceptor以前已經接收了一個提案號更高的prepare request的話, 那麼後面收到的prepare request就會被忽略, 這個例子中就是acceptor Z會忽略掉proposer A的請求(Z已經接收了B的提案n=4).
若是acceptor以前沒有接收過更高提案號的提案, 它會保證忽略其餘提案號比這個更低的請求(注意是包括prepare request和accept request),而後在prepare response中把它已經選中的提案號最高的提議(包括這個提議的值)發送給proposer.在這個例子就是acceptor X和Y給proposer B的響應(X和Y已經接受了一個B的[n=2,v=8]的提案,當再收到[n=4, v=5]的提案時, 它保證會忽略任何n<4的prepare request和accept request, 而後把[n=2, v=8]的prepare response回去給B)
圖4: acceptor Z 忽略了proposer A的請求, 由於它已經接收到了更高的提議號(4 > 2). acceptor X和Y給proposer B響應了它見過最高的提議號的提案, 並承諾會忽略提案號更小的提案
一旦proposer 收到了大多數acceptor的prepare response, 它就能夠開始給全部的acceptor發送accept request了. 由於proposer A接收到prepare response中代表在它以前沒有更早的提案. 因此它的accept request中的提案號和提議值都是跟prepare request中的同樣.然而,這個accept request被全部的acceptor都拒絕了,由於它們都承諾了不會接收提議號比4更新的提案(由於都見過proposer B的提案了)
Proposer B的accept request狀況就跟proposer A的有所不一樣了. 首先它的提案號仍是它以前的提案號(n=4), 可是提議值卻不是它以前的提議值了(它以前提議的是v=5), 而是它在prepare response中接收到的提議值(v=8)[3]
圖5: proposer B也發送了一個accept request給每個acceptor.acceptor request中的提案號是它以前的提案號(4), 而提議值是它在prepare response中收到的值(8, 來自proposer A的提案[n=2, v=8])
若是acceptor收到了一個提案號不小於它見過的accept request, 它會接受這個accept request而且發送一個通知給到learner節點. 當learner節點發現大多數acceptor都已經接受了一個值的時候,Paxos算法就認爲這個值已經被選中.
當一個值被paxos選中後,後續的流程中將不能改變這個值.例如,當另外一個proposer C發送一個提案號更高的prepare request(例如, [n=6, v=7])過來時,全部的acceptor都會響應它以前已經選中的提議(n=4,v=8).這會要求proposer C在後續的acceptor request中也只能發送[n=6, v=8]的提議, 即只能確認一遍已經選中的這個值. 再後面, 若是有少許的acceptor還沒選中一個值的話, 這個流程會保證最終全部的節點都會一致地選中同一個值.