一些進程,能夠發起提議一個值,一個一致性算法要保證這些值中只有一個被選定。若是沒有提議,就不能有值被選定。選定以後能夠learn到這個值。算法
acceptor、proposer之間是互相配合的關係而不是對立的。安全
paxos的推理過程不是必要的,而是經過不斷增強條件找到一種實現方式,因此paxos不是惟一的一致性算法協議。異步
應用場景:分佈式
安全性: 只有提議的值被選定,只有一個被選定,只有值被選定後才能learn到。 可用性: 最終值能選出來。選出來的值最終可以被learn到。server
經過消息進行交互,使用異步、非byzantine模型。 進程隨時可能失敗、重啓、或操做緩慢 消息可能丟失、重複,可是不會毀壞。進程
最簡單的方式是隻有一個acceptor,acceptor用接收到的第一個proposer提議的值做爲選定的值。雖然簡單,可是卻有單點問題,當acceptor失效的時候系統就執行不下去了。 因此天然地,咱們來使用多個acceptor的模型。 一個提議者proposer向多個acceptor發送提議,acceptor可能接受這個提議,如何肯定哪一個提議值被選定呢,在一個acceptor最多接受一個提議的狀況下,大於半數的acceptor接受的值被認爲選定。遍歷
若是不考慮進程失效和消息丟失的狀況,當只有一個proposer發出一個提議的狀況下,咱們還須要最終可以選定一個值。 咱們能夠進行一下需求增強 P1. acceptor必須接受它收到的第一個提議 可是這樣會有一個問題,不一樣的proposer可能會同時發出不一樣的提議,致使沒有一個提議被半數以上被接受。 結合P1和上面的問題,咱們獲得acceptor還須要接受更多的提議。咱們用一個序號來標識提議,proposer發送提議時須要生成序號來標識,這樣提議就擁有了提議號和提議的值。爲了不混亂,咱們要求不一樣的提議擁有不一樣的序號。序號的生成有各類實現方式,咱們這裏只是假設存在這樣一個發號器。當一個提議被大多數acceptor接受後,咱們就說這個提議和提議的值被選定了。咱們能夠容許多個提議被選定,可是必需要保證這些提議的值是同樣的。 經過引入提議號, P2. 若是一個有值v的提議被選定了,則每一個更高序號的被接受的提議的值都是v。 由於序號是總體有序的,因此條件P2可以保證關鍵的安全性屬性: 只有一個值可以被選定。 要被選定的話,提議須要至少被一個acceptor接受,因此咱們能夠繼續增強P2 P2a. 若是一個值爲v的提議被選定了,則每一個更高序號的被接受的提議的值都是v。 咱們如今還維護P1來確保至少有提議被選定。由於交互方式是異步的,可能出現當某個值被選定時還有一個acceptor c沒有收到過任何提議。假設這個時候一個新的proposer忽然醒過來了而後發起了一個更高序號的proposal而且值和選定的不同。P1要求c接受這個提議,會違反P2a。爲了同時保持P1和P2a須要增強P2a到: P2b. 若是一個值爲v的提議被選定了,則每一個任何Proposer發出的更高序號的提議的值必須爲v。 由於一個提議必需要先發起以後才能被接受,這樣P2b知足P2a,P2a又能知足P2。請求
下面就變成了如何知足P2b。 咱們先看下P2b擁有哪些特性: 假設某個值爲v序號爲m的提議被選定了,那麼對於任何n>m的提議的值都是v。客戶端
那麼任何m到n-1之間的提議。 若是提議值m被選中了,則一定存在一個包含大多數acceptor的集合C,其中每一個acceptor都接受了它。 意味着,集合C內的每一個acceptor都接受了m到n-1之間的提議,m到n-1之間的提議的值都是v。 由於任何包含大多數acceptor的集合S和集合C都有並集,因此能夠經過增強P2b來實現提議n的值也是v。 P2c. 對於任意的v和n, 若是一個序號爲n、值爲v的提議被提出了,存在一個包含大多數acceptor的集合S使得以下兩個條件至少知足一個 a) S中沒有acceptor接受過任何序號小於n的提議 b) v是S中已經接受過的序號小於n的提議中序號最大的提議的值。協議
經過P2c能夠推出P2b。 爲了維護P2c的不變性條件,proposer想要提出序號爲n的提議,必須知道acceptor接受過或將要接受的序號小於n的提議的最大提議的值。 得到一個已經接受過的提議的值是很簡單的,可是預測未來的接受是很是難的。與其嘗試預測將來,proposer能夠經過要求一個未來不會有這種接受狀況來控制。 換句話說,proposer要求acceptor們不能再接受序號小於n的提議了。這樣就能夠獲得以下的發起提議的算法。
假設acceptor已經收到了一個序號爲n的prepare請求,可是它已經回覆過一個序號大於n的prepare請求了,也就是許諾不會接受任何新的序號爲n的提議了。這樣,就沒必要回復這個prepare請求了,忽略便可。咱們還能夠忽略已經接受過的提議的prepare請求。 這樣,acceptor只須要記住它接受過的最大序號的提議和它回覆過的序號最大的prepare請求。由於P2c在生效的狀況下也要保持,因此acceptor必需要在實現和重啓後依然可以記住它的這些信息。proposer能夠放棄一個提議,只要再也不使用相同的序號發送提議。
因此這個算法操做包含兩個過程。 過程1. a) 一個proposer選擇一個提議序號n而後給acceptor的大多數集合發送prepare請求。 b) 若是acceptor收到了一個序號爲n的prepare請求,而且n大於它回覆過的全部prepare請求,則它會許諾再也不接受序號小於n的提議,而且返回已經接受過的最大序號的提議(若是有的話) 過程2. a) 若是proposer從acceptor中的大多數中收到了prepare請求(序號n)的回覆,則它會給這些acceptor發送accept請求,請求中爲序號爲n和值爲v的提議,v是恢復中序號最大的提議的值(或者沒有提議的狀況下能夠是任意值) b) 若是acceptor收到了序號爲n的accept請求, 則它會接受這個提議,除非它已經恢復了一個序號大於n的提議的prepare請求。
爲了得到已經選定的值,learner必須找出被大多數acceptor接收的值。一種顯然的算法就是每一個leaner遍歷全部的acceptor來獲得哪一個值被選定了。另外一種方式是從leader中選出一個來遍歷獲取而後通知其餘人。
liveness: 可能出現以下的相似活鎖的狀況,Proposer p使用提議序號n1完成了階段1,另外一個proposer q而後用大於n1的n2完成了階段1,p在階段2的acceptor請求被acceptor忽略掉了,由於acceptor許諾過不會接受任何序號小於n2的提議,而後p又開始用n3>n2來完成階段1,致使q的階段2被忽略,這樣如此反覆。 爲了保證進度,要選擇一個惟一的proposer來做爲惟一的發起提議的proposal,能夠經過選舉來獲得這個惟一的Proposer。
實現狀態機 實現分佈式系統的一種簡單的方式就是讓許多客戶端發送命令給一箇中央server,這個server是接收執行客戶端請求的肯定狀態機。狀態機有當前狀態,而後經過執行命令產生一個輸出並達到下一個狀態。例如分佈式銀行系統的客戶端是出納員,狀態機能夠是包含全部用戶的帳戶餘額,一個取款操做就是在餘額大於取款金額的狀況下減小這個帳戶的餘額。只有一箇中央server的實如今server失效的狀況下也失效了。因此咱們使用一些server,每一個server都獨立的實現這個狀態機,由於狀態機是肯定的,因此全部的初始狀態相同的server只要接受相同序列的命令,都會產生相同序列的狀態和輸出。爲了保證全部的server執行相同序列的狀態機命令,咱們把肯定每一個命令做爲單獨的paxos算法示例。 正常狀況下,一個單獨的server被選舉爲leader,來做爲proposer,客戶端發送命令給leader,leader決定這些命令的順序。