Paxos共识算法详解
在一個(gè)分布式系統(tǒng)中,由于節(jié)點(diǎn)故障、網(wǎng)絡(luò)延遲等各種原因,根據(jù)CAP理論,我們只能保證一致性(Consistency)、可用性(Availability)、分區(qū)容錯(cuò)性(Partition Tolerance) 中的兩個(gè)。
對于一致性要求高的系統(tǒng),比如銀行取款機(jī),就會(huì)選擇犧牲可用性,故障時(shí)拒絕服務(wù)。MongoDB、Redis、MapReduce使用這種方案。
對于靜態(tài)網(wǎng)站、實(shí)時(shí)性較弱的查詢類數(shù)據(jù)庫,會(huì)犧牲一致性,允許一段時(shí)間內(nèi)不一致。簡單分布式協(xié)議Gossip,數(shù)據(jù)庫CouchDB、Cassandra使用這種方案。
圖1
如圖1所示,一致性問題,可以根據(jù)是否存在惡意節(jié)點(diǎn)分類兩類。無惡意節(jié)點(diǎn),是指節(jié)點(diǎn)會(huì)丟失、重發(fā)、不響應(yīng)消息,但不會(huì)篡改消息。而惡意節(jié)點(diǎn)可能會(huì)篡改消息。有惡意節(jié)點(diǎn)的問題稱為拜占庭將軍問題,不在今天的討論范圍。Paxos很好地解決了無惡意節(jié)點(diǎn)的分布式一致性問題。
背景
1990年,Leslie Lamport在論文《The Part-Time Parliament》中提出Paxos算法。由于論文使用故事的方式,沒有使用數(shù)學(xué)證明,起初并沒有得到重視。直到1998年該論文才被正式接受。后來2001年Lamport又重新組織了論文,發(fā)表了《Paxos Made Simple》。作為分布式系統(tǒng)領(lǐng)域的早期貢獻(xiàn)者,Lamport獲得了2013年圖靈獎(jiǎng)。
Paxos算法廣泛應(yīng)用在分布式系統(tǒng)中,Google Chubby的作者M(jìn)ike Burrows說:“這個(gè)世界上只有一種一致性算法,那就是 Paxos(There is only one consensus protocol, and that's Paxos)”。
后來的Raft算法、是對Paxos的簡化和改進(jìn),變得更加容易理解和實(shí)現(xiàn)。
Paxos類型
Paxos本來是虛構(gòu)故事中的一個(gè)小島,議會(huì)通過表決來達(dá)成共識。但是議員可能離開,信使可能走丟,或者重復(fù)傳遞消息。對應(yīng)到分布式系統(tǒng)的節(jié)點(diǎn)故障和網(wǎng)絡(luò)故障。
圖2
如圖2所示,假設(shè)議員要提議中午吃什么。如果有一個(gè)或者多個(gè)人同時(shí)提議,但一次只能通過一個(gè)提議,這就是Basic Paxos,是Paxos中最基礎(chǔ)的協(xié)議。
顯然Basic Paxos是不夠高效的,如果將Basic Paxos并行起來,同時(shí)提出多個(gè)提議,比如中午吃什么、吃完去哪里嗨皮、誰請客等提議,議員也可以同時(shí)通過多個(gè)提議。這就是Multi-Paxos協(xié)議。
Basic Paxos
角色
Paxos算法存在3種角色:Proposer、Acceptor、Learner,在實(shí)現(xiàn)中一個(gè)節(jié)點(diǎn)可以擔(dān)任多個(gè)角色。
圖3
- Proposer負(fù)責(zé)提出提案
- Acceptor負(fù)責(zé)對提案進(jìn)行投票
- Learner獲取投票結(jié)果,并幫忙傳播
Learner不參與投票過程,為了簡化描述,我們直接忽略掉這個(gè)角色。
算法
運(yùn)行過程分為兩個(gè)階段,Prepare階段和Accept階段。
Proposer需要發(fā)出兩次請求,Prepare請求和Accept請求。Acceptor根據(jù)其收集的信息,接受或者拒絕提案。
Prepare階段
- Proposer選擇一個(gè)提案編號n,發(fā)送Prepare(n)請求給超過半數(shù)(或更多)的Acceptor。
- Acceptor收到消息后,如果n比它之前見過的編號大,就回復(fù)這個(gè)消息,而且以后不會(huì)接受小于n的提案。另外,如果之前已經(jīng)接受了小于n的提案,回復(fù)那個(gè)提案編號和內(nèi)容給Proposer。
Accept階段
- 當(dāng)Proposer收到超過半數(shù)的回復(fù)時(shí),就可以發(fā)送Accept(n, value)請求了。 n就是自己的提案編號,value是Acceptor回復(fù)的最大提案編號對應(yīng)的value,如果Acceptor沒有回復(fù)任何提案,value就是Proposer自己的提案內(nèi)容。
- Acceptor收到消息后,如果n大于等于之前見過的最大編號,就記錄這個(gè)提案編號和內(nèi)容,回復(fù)請求表示接受。
- 當(dāng)Proposer收到超過半數(shù)的回復(fù)時(shí),說明自己的提案已經(jīng)被接受。否則回到第一步重新發(fā)起提案。
完整算法如圖4所示:
圖4
Acceptor需要持久化存儲minProposal、acceptedProposal、acceptedValue這3個(gè)值。
三種情況
Basic Paxos共識過程一共有三種可能的情況。下面分別進(jìn)行介紹。
情況1:提案已接受
如圖5所示。X、Y代表客戶端,S1到S5是服務(wù)端,既代表Proposer又代表Acceptor。為了防止重復(fù),Proposer提出的編號由兩部分組成:
序列號.Server ID
例如S1提出的提案編號,就是1.1、2.1、3.1……
圖5 以上圖片來自Paxos lecture (Raft user study)第13頁
這個(gè)過程表示,S1收到客戶端的提案X,于是S1作為Proposer,給S1-S3發(fā)送Prepare(3.1)請求,由于Acceptor S1-S3沒有接受過任何提案,所以接受該提案。然后Proposer S1-S3發(fā)送Accept(3.1, X)請求,提案X成功被接受。
在提案X被接受后,S5收到客戶端的提案Y,S5給S3-S5發(fā)送Prepare(4.5)請求。對S3來說,4.5比3.1大,且已經(jīng)接受了X,它會(huì)回復(fù)這個(gè)提案 (3.1, X)。S5收到S3-S5的回復(fù)后,使用X替換自己的Y,于是發(fā)送Accept(4.5, X)請求。S3-S5接受提案。最終所有Acceptor達(dá)成一致,都擁有相同的值X。
這種情況的結(jié)果是:新Proposer會(huì)使用已接受的提案
情況2:提案未接受,新Proposer可見
圖6 以上圖片來自Paxos lecture (Raft user study)第14頁
如圖6所示,S3接受了提案(3.1, X),但S1-S2還沒有收到請求。此時(shí)S3-S5收到Prepare(4.5),S3會(huì)回復(fù)已經(jīng)接受的提案(3.1, X),S5將提案值Y替換成X,發(fā)送Accept(4.5, X)給S3-S5,對S3來說,編號4.5大于3.1,所以會(huì)接受這個(gè)提案。
然后S1-S2接受Accept(3.1, X),最終所有Acceptor達(dá)成一致。
這種情況的結(jié)果是:新Proposer會(huì)使用已提交的值,兩個(gè)提案都能成功
情況3:提案未接受,新Proposer不可見
圖7 以上圖片來自Paxos lecture (Raft user study)第15頁
如圖7所示,S1接受了提案(3.1, X),S3先收到Prepare(4.5),后收到Accept(3.1, X),由于3.1小于4.5,會(huì)直接拒絕這個(gè)提案。所以提案X無法收到超過半數(shù)的回復(fù),這個(gè)提案就被阻止了。提案Y可以順利通過。
這種情況的結(jié)果是:新Proposer使用自己的提案,舊提案被阻止
活鎖 (livelock)
活鎖發(fā)生的幾率很小,但是會(huì)嚴(yán)重影響性能。就是兩個(gè)或者多個(gè)Proposer在Prepare階段發(fā)生互相搶占的情形。
圖8 以上圖片來自Paxos lecture (Raft user study)第16頁
解決方案是Proposer失敗之后給一個(gè)隨機(jī)的等待時(shí)間,這樣就減少同時(shí)請求的可能。
Multi-Paxos
上一小節(jié)提到的活鎖,也可以使用Multi-Paxos來解決。它會(huì)從Proposer中選出一個(gè)Leader,只由Leader提交Proposal,還可以省去Prepare階段,減少了性能損失。當(dāng)然,直接把Basic Paxos的多個(gè)Proposer的機(jī)制搬過來也是可以的,只是性能不夠高。
將Basic Paxos并行之后,就可以同時(shí)處理多個(gè)提案了,因此要能存儲不同的提案,也要保證提案的順序。
Acceptor的結(jié)構(gòu)如圖9所示,每個(gè)方塊代表一個(gè)Entry,用于存儲提案值。用遞增的Index來區(qū)分Entry。
圖9
Multi-Paxos需要解決幾個(gè)問題,我們逐個(gè)來看。
1. Leader選舉
一個(gè)最簡單的選舉方法,就是Server ID最大的當(dāng)Leader。
每個(gè)Server間隔T時(shí)間向其他Server發(fā)送心跳包,如果一個(gè)Server在2T時(shí)間內(nèi)沒有收到來自更高ID的心跳,那么它就成為Leader。
其他Proposer,必須拒絕客戶端的請求,或?qū)⒄埱筠D(zhuǎn)發(fā)給Leader。
當(dāng)然,還可以使用其他更復(fù)雜的選舉方法,這里不再詳述。
2. 省略Prepare階段
Prepare的作用是阻止舊的提案,以及檢查是否有已接受的提案值。
當(dāng)只有一個(gè)Leader發(fā)送提案的時(shí)候,Prepare是不會(huì)產(chǎn)生沖突的,可以省略Prepare階段,這樣就可以減少一半RPC請求。
Prepare請求的邏輯修改為:
- Acceptor記錄一個(gè)全局的最大提案編號
- 回復(fù)最大提案編號,如果當(dāng)前entry以及之后的所有entry都沒有接受任何提案,回復(fù)noMoreAccepted
當(dāng)Leader收到超過半數(shù)的noMoreAccepted回復(fù),之后就不需要Prepare階段了,只需要發(fā)送Accept請求。直到Accept被拒絕,就重新需要Prepare階段。
3. 完整信息流
目前為止信息是不完整的。
- Basic Paxos只需超過半數(shù)的節(jié)點(diǎn)達(dá)成一致。但是在Multi-Paxos中,這種方式可能會(huì)使一些節(jié)點(diǎn)無法得到完整的entry信息。我們希望每個(gè)節(jié)點(diǎn)都擁有全部的信息。
- 只有Proposer知道一個(gè)提案是否被接受了(根據(jù)收到的回復(fù)),而Acceptor無法得知此信息。
第1個(gè)問題的解決方案很簡單,就是Proposer給全部節(jié)點(diǎn)發(fā)送Accept請求。
第2個(gè)問題稍微復(fù)雜一些。首先,我們可以增加一個(gè)Success RPC,讓Proposer顯式地告訴Acceptor,哪個(gè)提案已經(jīng)被接受了,這個(gè)是完全可行的,只不過還可以優(yōu)化一下,減少請求次數(shù)。
我們在Accept請求中,增加一個(gè)firstUnchosenIndex參數(shù),表示Proposer的第一個(gè)未接受的Index,這個(gè)參數(shù)隱含的意思是,對該P(yáng)roposer來說,小于Index的提案都已經(jīng)被接受了。因此Acceptor可以利用這個(gè)信息,把小于Index的提案標(biāo)記為已接受。另外要注意的是,只能標(biāo)記該P(yáng)roposer的提案,因?yàn)槿绻l(fā)生Leader切換,不同的Proposer擁有的信息可能不同,不區(qū)分Proposer直接標(biāo)記的話可能會(huì)不一致。
圖10
如圖10所示,Proposer正在準(zhǔn)備提交Index=2的Accept請求,0和1是已接受的提案,因此firstUnchosenIndex=2。當(dāng)Acceptor收到請求后,比較Index,就可以將Dumplings提案標(biāo)記為已接受。
由于之前提到的Leader切換的情況,仍然需要顯式請求才能獲得完整信息。在Acceptor回復(fù)Accept消息時(shí),帶上自己的firstUnchosenIndex。如果比Proposer的小,那么就需要發(fā)送Success(index, value),Acceptor將收到的index標(biāo)記為已接受,再回復(fù)新的firstUnchosenIndex,如此往復(fù)直到兩者的index相等。
總結(jié)
Paxos是分布式一致性問題中的重要共識算法。這篇文章分別介紹了最基礎(chǔ)的Basic Paxos,和能夠并行的Multi-Paxos。
在Basic Paxos中,介紹了3種基本角色Proposer、Acceptor、Learner,以及提案時(shí)可能發(fā)生的3種基本情況。在Multi-Paxos中,介紹了3個(gè)需要解決的問題:Leader選舉、Prepare省略、完整信息流。
在下一篇文章中,我們將實(shí)現(xiàn)一個(gè)簡單的demo來驗(yàn)證這個(gè)算法,實(shí)現(xiàn)過程將會(huì)涉及到更多的細(xì)節(jié)。
Reference
分布式一致性與共識算法
Paxos 算法與 Raft 算法
Paxos
Paxos Made Simple
Paxos lecture (Raft user study)
YouTube | Paxos lecture (Raft user study)
版權(quán)
本作品采用CC BY 4.0許可協(xié)議,轉(zhuǎn)載時(shí)請注明鏈接。
總結(jié)
以上是生活随笔為你收集整理的Paxos共识算法详解的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【布莱克智讯之声公众号】 精彩图文分类导
- 下一篇: dtoj#4263. duliu