分布式系统概念 | 一致性协议:拜占庭将军问题、Paxos、Raft
文章目錄
- 拜占庭將軍問(wèn)題
- Paxos
-
- 問(wèn)題描述
- 執(zhí)行過(guò)程
-
- Prepare階段
- Accept階段
- Learner獲取提案
- 活鎖問(wèn)題
- Raft
-
- 狀態(tài)機(jī)
- 執(zhí)行流程
-
- 主節(jié)點(diǎn)選舉
- 數(shù)據(jù)同步
拜占庭將軍問(wèn)題
拜占庭位于如今的土耳其的伊斯坦布爾,是東羅馬帝國(guó)的首都。由于當(dāng)時(shí)拜占庭羅馬帝國(guó)國(guó)土遼闊,為了達(dá)到防御目的,每個(gè)軍隊(duì)都分隔很遠(yuǎn),將軍與將軍之間只能靠信差傳消息。在戰(zhàn)爭(zhēng)的時(shí)候,拜占庭軍隊(duì)內(nèi)所有將軍和副官必須達(dá)成一致的共識(shí),決定是否有贏的機(jī)會(huì)才去攻打敵人的陣營(yíng)。但是,在軍隊(duì)內(nèi)有可能存有叛徒和敵軍的間諜,叛徒可以任意行動(dòng)以達(dá)到以下目標(biāo):欺騙某些將軍采取進(jìn)攻行動(dòng);促成一個(gè)不是所有將軍都同意的決定,如當(dāng)將軍們不希望進(jìn)攻時(shí)促成進(jìn)攻行動(dòng);或者迷惑某些將軍,使他們無(wú)法做出決定。如果叛徒達(dá)到了這些目的之一,則任何攻擊行動(dòng)的結(jié)果都是注定要失敗的,只有完全達(dá)成一致的努力才能獲得勝利。
這時(shí)候,在已知有成員謀反的情況下,其余忠誠(chéng)的將軍在不受叛徒的影響下如何達(dá)成一致的協(xié)議,拜占庭問(wèn)題就此形成 。
拜占庭將軍問(wèn)題的核心在于在缺少可信任的中央節(jié)點(diǎn)和可信任的通道的情況下,分布在不同地方的各個(gè)節(jié)點(diǎn)應(yīng)如何達(dá)成共識(shí)。我們可以將這個(gè)問(wèn)題延伸到分布式計(jì)算領(lǐng)域中。
在分布式計(jì)算領(lǐng)域中,試圖在異步系統(tǒng)和不可靠的通道上達(dá)到一致性狀態(tài)是不可能的,因此在對(duì)一致性的研究過(guò)程中,都往往假設(shè)信道是可靠的,而事實(shí)上,大多數(shù)系統(tǒng)都是部署在同一個(gè)局域網(wǎng)中,因此消息被篡改的情況非常罕見(jiàn);另一方面,由于機(jī)器硬件和網(wǎng)絡(luò)原因?qū)е碌南⒉煌暾麊?wèn)題,也僅僅只需要一套簡(jiǎn)單的校驗(yàn)算法即可避免。
那么當(dāng)我們假設(shè)拜占庭問(wèn)題不存在(所有消息都是完整的,沒(méi)有被篡改),那么這種情況下需要什么算法來(lái)保證一致性呢?拜占庭將軍問(wèn)題的提出者Lamport提出了一種非拜占庭將軍問(wèn)題的一致性解決方案——Paxos算法
Paxos
問(wèn)題描述
與拜占庭將軍問(wèn)題一樣,Lamport同樣使用故事的方式來(lái)提出Paxos問(wèn)題
希臘島嶼Paxon上的議員在議會(huì)大廳中表決通過(guò)法律,并通過(guò)服務(wù)員傳遞紙條的方式交流信息,每個(gè)議員會(huì)將通過(guò)的法律記錄在自己的賬目上。問(wèn)題在于執(zhí)法者和服務(wù)員都不可靠,他們隨時(shí)會(huì)因?yàn)楦鞣N事情離開(kāi)議會(huì)大廳,并隨時(shí)可能有新的議員進(jìn)入議會(huì)大廳進(jìn)行法律表決,使用何種方式能夠使得這個(gè)表決過(guò)程正常進(jìn)行,且通過(guò)的法律不發(fā)生矛盾。
不難看出故事中的議會(huì)大廳就是分布式系統(tǒng),議員對(duì)應(yīng)節(jié)點(diǎn)或進(jìn)程,服務(wù)員傳遞紙條的過(guò)程就是消息傳遞的過(guò)程,法律即是我們需要保證一致性的值。議員和服務(wù)員的進(jìn)出對(duì)應(yīng)著節(jié)點(diǎn)/網(wǎng)絡(luò)的失效和加入,議員的賬目對(duì)應(yīng)節(jié)點(diǎn)中的持久化存儲(chǔ)設(shè)備。上面表決過(guò)程的正常進(jìn)行可以表述為進(jìn)展需求:當(dāng)大部分議員在議會(huì)大廳呆了足夠長(zhǎng)時(shí)間,且期間沒(méi)有議員進(jìn)入或者退出,那么提出的法案應(yīng)該被通過(guò)并被記錄在每個(gè)議員的賬目上。
Paxos算法需要解決的問(wèn)題就是如何在上述分布式系統(tǒng)中,快速且正確地在集群內(nèi)部對(duì)某個(gè)數(shù)據(jù)的值達(dá)成一致,并且保證不論發(fā)生以上任何異常,都不會(huì)破壞整個(gè)系統(tǒng)的一致性。
Paxos解決的問(wèn)題
為了能夠使得表決過(guò)程正常進(jìn)行,且通過(guò)的法律不發(fā)生矛盾,那么我們需要保證以下幾點(diǎn)
- 在這些被提出的提案中,最后只能有一個(gè)被選定
- 如果沒(méi)有提案被提出,那么就不會(huì)有被選定的提案
- 當(dāng)一個(gè)提案被選定后,節(jié)點(diǎn)們應(yīng)該可以獲取被選定的提案信息
在Paxos算法中,主要有以下三種角色,并且一個(gè)節(jié)點(diǎn)可能同時(shí)擔(dān)任幾種角色
- 提議者(Proposer):負(fù)責(zé)提出提議;
- 接受者(Acceptor):對(duì)每個(gè)提議進(jìn)行投票;
- 告知者(Learner):被告知投票的結(jié)果,不參與投票過(guò)程。
各節(jié)點(diǎn)之間的關(guān)系
同時(shí),假設(shè)不同參與者之間通過(guò)收發(fā)消息來(lái)進(jìn)行通信,那么我們需要具備以下條件
- 每個(gè)參與者可能會(huì)因?yàn)槌鲥e(cuò)而導(dǎo)致停止、重啟等情況,
- 雖然消息在傳輸過(guò)程中可能會(huì)出現(xiàn)不可預(yù)知的延遲、重復(fù)、丟失等情況,但是消息不會(huì)被損壞或篡改(即不存在拜占庭問(wèn)題)
執(zhí)行過(guò)程
首先我們規(guī)定一個(gè)提議包含兩個(gè)字段:[n, v],其中 n 為序號(hào)(具有唯一性),v 為提議值。
Paxos執(zhí)行過(guò)程主要分為兩個(gè)階段,與之前講過(guò)的2PC(二階段提交協(xié)議)類(lèi)似。
- Prepare階段
- Accept階段
如下圖
Paxos算法流程
Prepare階段
- 首先,每個(gè)Proposer都會(huì)向所有的Acceptor發(fā)送一個(gè)Prepare請(qǐng)求。
- 當(dāng)Acceptor接收到一個(gè)Prepare請(qǐng)求,提議內(nèi)容為[n1,v1],由于之前還未接受過(guò)Prepare請(qǐng)求,那么它會(huì)返回一個(gè)[no previous]的Prepare響應(yīng),并且設(shè)置當(dāng)前接受的提議為[n1,v1],同時(shí)保證以后不會(huì)再接收序號(hào)小于n1的提議。
- 如果Acceptor再次收到一個(gè)Prepare請(qǐng)求,提議內(nèi)容為[n2,v2],此時(shí)會(huì)有兩種情況。
- 如果n2 < n1,此時(shí)Acceptor就會(huì)直接拋棄該請(qǐng)求
- 如果n2 >= n1,此時(shí)Acceptor就會(huì)發(fā)送一個(gè)[n1,v1]的Prepare響應(yīng),設(shè)置當(dāng)前接受到的提議為[n2,v2],同時(shí)保證與上一步邏輯相同,保證以后不會(huì)再接受序號(hào)小于n2的提議。
Accept階段
- 當(dāng)一個(gè)Proposer接收到超過(guò)一半的Acceptor的Prepare響應(yīng)時(shí),此時(shí)它就會(huì)發(fā)送一個(gè)針對(duì)[n,v]提案的Accept請(qǐng)求給Acceptor。
- 如果一個(gè)Acceptor收到一個(gè)編號(hào)為n的提案的Accept請(qǐng)求,此時(shí)有兩種情況。
- 如果該Acceptor沒(méi)有對(duì)編號(hào)大于n的Prepare請(qǐng)求做出過(guò)響應(yīng),它就會(huì)接受該提案,并發(fā)送Learn提議給Learner
- 如果該Acceptor接受過(guò)編號(hào)大于n的Prepare請(qǐng)求,那么它就會(huì)拒絕、不回應(yīng)或回復(fù)error。(如果一個(gè)Proposer沒(méi)有收到過(guò)半的回應(yīng),那他就會(huì)重新進(jìn)入第一階段,遞增提案號(hào)后重新提出Prepare請(qǐng)求)
在上述過(guò)程中,每一個(gè)Proposer都有可能會(huì)產(chǎn)生多個(gè)提案。但只要每個(gè)Proposer都遵循如上述算法運(yùn)行,就一定能保證算法執(zhí)行的正確性。
Learner獲取提案
在Accept階段之后Acceptor選定提案后,根據(jù)具體的應(yīng)用場(chǎng)景不同,Learner主要采用以下三種方案來(lái)學(xué)習(xí)選定的提案
| 方案 | 優(yōu)點(diǎn) | 缺點(diǎn) |
|---|---|---|
| Acceptor直接將提議發(fā)給所有的Learner | Learner能夠快速獲取被選定的提議 | 通信次數(shù)過(guò)多,每個(gè)Acceptor都要和Learn產(chǎn)生通信(M * N) |
| Acceptor接受提議后將提議發(fā)給主Learner,主Learner再通知其他Learner | 通信次數(shù)減少(M + N - 1) | 單點(diǎn)問(wèn)題(主Learner出現(xiàn)故障就會(huì)崩潰) |
| Acceptor將提議發(fā)一個(gè)Learner集合,Learener集合再發(fā)給其他Learener | 解決了單點(diǎn)問(wèn)題,集合中Learner個(gè)數(shù)越多就越可靠 | 網(wǎng)絡(luò)通信復(fù)雜度變高 |
當(dāng)Learner們發(fā)現(xiàn)有大多數(shù)的Acceptor接受了某一個(gè)提議,那么該提議的提議值則就是Paxos最終選擇出來(lái)的結(jié)果。
活鎖問(wèn)題
在Paxos算法實(shí)際運(yùn)作的時(shí)候還存在這樣一種極端的情況——當(dāng)有兩個(gè)Proposer依次提出了一系列編號(hào)遞增的提案,此時(shí)就會(huì)導(dǎo)致陷入死循環(huán),無(wú)法完成第二階段,也就是無(wú)法選定一個(gè)提案,如以下場(chǎng)景。
- Proposer P1發(fā)出編號(hào)為n1的Prepare請(qǐng)求,收到過(guò)半響應(yīng),完成了階段一的流程。
- 同時(shí),Proposer P2發(fā)出編號(hào)為n2的Prepare請(qǐng)求(n2 > n1),也收到了過(guò)半的響應(yīng),完成了階段一的流程,并且Acceptor承諾不再接受編號(hào)小于n2的提案。
- P1進(jìn)入第二階段時(shí),由于Acceptor不接受小于n2的提案,所以P1重新回到第一階段,遞增提案號(hào)為n3后重新發(fā)出Prepare請(qǐng)求
- 緊接著,P2進(jìn)入第二階段,由于Acceptor不接受小于n3的提案,此時(shí)它也重新回到第一階段,遞增提案號(hào)后重新發(fā)出Prepare請(qǐng)求
- 于是P1、P2陷入了死循環(huán),誰(shuí)都無(wú)法完成階段二,這也就導(dǎo)致了沒(méi)有value能被選定。
為了保證Paxos算法的可持續(xù)性,以避免陷入上述提到的死循環(huán),就必須選擇一個(gè)主Proposer,并規(guī)定只有主Proposer才能夠提出提案。這樣一來(lái),只要主Proposer和過(guò)半的Acceptor能夠正常進(jìn)行網(wǎng)絡(luò)通信,那么肯定會(huì)有一個(gè)提案被批準(zhǔn)(第二階段的accept),則可以解決死循環(huán)導(dǎo)致的活鎖問(wèn)題。
Raft
從上面可以看出,Paxos算法相對(duì)來(lái)說(shuō)較為復(fù)雜且難以理解,因此在后來(lái)又出現(xiàn)了一種用于替代Paxos的算法——Raft
Raft算法是一種簡(jiǎn)單易懂的共識(shí)算法,所謂共識(shí),就是多個(gè)節(jié)點(diǎn)對(duì)某個(gè)事情達(dá)成一致的看法,即使是在部分節(jié)點(diǎn)故障、網(wǎng)絡(luò)延時(shí)、網(wǎng)絡(luò)分割的情況下。它依靠狀態(tài)機(jī)和主從同步的方式,在各個(gè)節(jié)點(diǎn)之間實(shí)現(xiàn)數(shù)據(jù)的一致性。
Raft算法的核心主要為以下兩部分,下面將進(jìn)行具體講解
- 主節(jié)點(diǎn)選舉(Leader Election)
- 數(shù)據(jù)同步(Log Replication)
狀態(tài)機(jī)
在Raft中節(jié)點(diǎn)中存在三種狀態(tài),狀態(tài)之間可以相互進(jìn)行轉(zhuǎn)換
-
Leader(主節(jié)點(diǎn))
-
Follower(從節(jié)點(diǎn))
-
Candidate(競(jìng)選節(jié)點(diǎn))
同時(shí),每個(gè)節(jié)點(diǎn)上會(huì)存放一個(gè)倒計(jì)時(shí)器(Election Timeout),時(shí)間隨機(jī)在150ms到300ms之間。Leader節(jié)點(diǎn)會(huì)周期性的向所有Follower發(fā)送一個(gè)心跳包(Heartbeat),收到心跳包的節(jié)點(diǎn)會(huì)將其計(jì)時(shí)器清零后重新計(jì)時(shí),如果在倒計(jì)時(shí)結(jié)束前沒(méi)有收到Leader的心跳包,此時(shí)Follower就會(huì)變?yōu)镃andidate,開(kāi)始進(jìn)入競(jìng)選狀態(tài)。
具體的狀態(tài)轉(zhuǎn)移如下圖
狀態(tài)轉(zhuǎn)換圖
執(zhí)行流程
主節(jié)點(diǎn)選舉
介紹了狀態(tài)機(jī)后,下面就來(lái)看看主節(jié)點(diǎn)的選舉流程
第一步,在一開(kāi)始時(shí),由于沒(méi)有Leader,所以此時(shí)所有節(jié)點(diǎn)的身份都是Follower,每一個(gè)節(jié)點(diǎn)上都有著自己的計(jì)數(shù)器,當(dāng)計(jì)時(shí)器達(dá)到了超時(shí)時(shí)間后,該節(jié)點(diǎn)就會(huì)轉(zhuǎn)換為Candidate,開(kāi)始選舉過(guò)程。
第一步:開(kāi)始選舉
第二步,成為Candidate的節(jié)點(diǎn)首先會(huì)給自己投一張票,然后向集群中的其他所有節(jié)點(diǎn)發(fā)起投票請(qǐng)求。
第二步:開(kāi)始拉票
第三步,收到投票請(qǐng)求并且還未投票的Follower節(jié)點(diǎn)會(huì)向發(fā)起者回復(fù)投票反饋,如果收到了超過(guò)半數(shù)的回復(fù),此時(shí)Candidate選舉成功,狀態(tài)轉(zhuǎn)變?yōu)長(zhǎng)eader。
第三步:選舉成功
第四步,Leader節(jié)點(diǎn)會(huì)立刻向其他節(jié)點(diǎn)發(fā)出通告,告知其他節(jié)點(diǎn)它已成功選舉成Leader,收到通知的節(jié)點(diǎn)會(huì)轉(zhuǎn)換為Follower。并且Leader會(huì)周期性的發(fā)送心跳包給所有Follower來(lái)表明它還存活,當(dāng)Follower接收到心跳包時(shí),就會(huì)重置計(jì)時(shí)器。
第四步:Leader向其他節(jié)點(diǎn)發(fā)送通知
一旦Leader節(jié)點(diǎn)掛掉,它就無(wú)法發(fā)出心跳包來(lái)重置Follower的倒計(jì)時(shí)器,那么當(dāng)Follower的超時(shí)時(shí)間到達(dá)后,其就會(huì)轉(zhuǎn)換成Candidate節(jié)點(diǎn),再次重復(fù)以上過(guò)程。
上面介紹的是單節(jié)點(diǎn)的選舉,倘若同時(shí)有多個(gè)Follower同時(shí)倒計(jì)時(shí)結(jié)束后成為Candidate,同時(shí)開(kāi)始選舉,并且在選舉過(guò)程中所獲得的票數(shù)相同,此時(shí)就陷入了僵局,誰(shuí)都無(wú)法成為L(zhǎng)eader。
多個(gè)Candidate選舉時(shí)出現(xiàn)僵局
在重新選舉時(shí),由于每個(gè)節(jié)點(diǎn)設(shè)置的超時(shí)時(shí)間都是隨機(jī)的,因此下一次同時(shí)出現(xiàn)多個(gè)Candidate并獲得同樣票數(shù)導(dǎo)致選舉失敗的情況的概率則非常低。
隨機(jī)化超時(shí)時(shí)間避免沖突
數(shù)據(jù)同步
Raft中數(shù)據(jù)同步的方式與之前寫(xiě)過(guò)的2PC(二階段提交協(xié)議)有一些相似,也是分為投票和提交兩個(gè)階段,具體流程如下。
第一步,客戶(hù)端將修改傳入Leader中(此時(shí)修改并沒(méi)有提交,只是寫(xiě)入日志中)。
客戶(hù)端將修改傳入Leader
第二步,Leader將修改復(fù)制到集群內(nèi)的所有Follower節(jié)點(diǎn)上,如果復(fù)制失敗,會(huì)不斷進(jìn)行重試直至成功。
Leader將修改復(fù)制到所有Follower
第三步,Follow節(jié)點(diǎn)們成功接收到復(fù)制的數(shù)據(jù)后,會(huì)反饋結(jié)果給Leader節(jié)點(diǎn),如果Leader節(jié)點(diǎn)接收到超過(guò)半數(shù)的Follower反饋,則表明復(fù)制成功,于是提交自己的數(shù)據(jù),并且通知客戶(hù)端數(shù)據(jù)提交成功。
Follower接受成功后反饋結(jié)果
第四步,提交成功后,Leader會(huì)通知所有的Follower讓它們也提交修改,此時(shí)所有節(jié)點(diǎn)的值達(dá)成一致,完成數(shù)據(jù)同步流程。
Leader通知所有節(jié)點(diǎn)提交,完成數(shù)據(jù)同步
為了便于理解,可以結(jié)合下面的Raft原理動(dòng)畫(huà)一同學(xué)習(xí)。
Raft原理動(dòng)畫(huà)
除了上面介紹的Paxos、Raft,還有其他的一些解決分布式一致性的共識(shí)算法,如Zookeeper使用的ZAB,區(qū)塊鏈中使用的PBFT等,在未來(lái)的博客中,如果有機(jī)會(huì)我還會(huì)繼續(xù)為大家分享這些內(nèi)容。
總結(jié)
以上是生活随笔為你收集整理的分布式系统概念 | 一致性协议:拜占庭将军问题、Paxos、Raft的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: uc3842开关电源电路图_UC3842
- 下一篇: 苹果正招聘更多人才 让生成式AI能在你的