paxos
聲明:
- 本文思路完成模仿 朱一聰 老師的的 如何淺顯易懂地解說 Paxos 而得,版權(quán)屬于 朱一聰 老師 。只是為了自己理解更加透徹,又重新推導(dǎo)了一下而已。文章發(fā)出已經(jīng)獲得 朱一聰 老師的同意。
- 本文最后結(jié)論完全引用 Paxos Made Simple 中文翻譯版
- 學(xué)習(xí) paxos 請(qǐng)優(yōu)先選擇 Paxos Made Simple 和 Paxos lecture,不要選擇本文。本文僅能起到引導(dǎo)思路的作用
- 文章肯定有不嚴(yán)謹(jǐn),推導(dǎo)不嚴(yán)謹(jǐn)?shù)牡胤剑瑲g迎討論。
背景:
在一個(gè)高可用分布式存儲(chǔ)系統(tǒng)中,如果只使用一臺(tái)機(jī)器,只要這臺(tái)機(jī)器故障,系統(tǒng)就會(huì)崩潰。所以肯定需要多臺(tái)機(jī)器,但是由于網(wǎng)絡(luò)延遲,機(jī)器崩潰等原因,多臺(tái)機(jī)器對(duì)于數(shù)據(jù)很難達(dá)成共識(shí)(Consensus not Consistency)。而 paxos 協(xié)議就是用來使各個(gè)機(jī)器達(dá)成共識(shí)的協(xié)議。
如何理解共識(shí)(Consensus):
共識(shí)就是在一個(gè)或多個(gè)進(jìn)程提議了一個(gè)值應(yīng)當(dāng)是什么后,使系統(tǒng)中所有進(jìn)程對(duì)這個(gè)值達(dá)成一致意見。但是必須明確:在一個(gè)完全異步且可能出現(xiàn)任何故障的系統(tǒng)中,不存在一個(gè)算法可以確保達(dá)到共識(shí)(FLP Impossibility)。
前提:
需要保證安全性:
- 只有被提出的提案才能被選定
- 只能有一個(gè)值被選定
- 如果某個(gè)進(jìn)程認(rèn)為某個(gè)提案被選定了,那么這個(gè)提案必須是真的被選定的那個(gè)
可能出現(xiàn)的場(chǎng)景
- 進(jìn)程之間的通信可能出現(xiàn)故障
- 每個(gè)進(jìn)程都可能提出不同的值
- 每個(gè)進(jìn)程也可能隨時(shí)崩潰
- 進(jìn)程之間傳輸?shù)臄?shù)據(jù)不會(huì)篡改
達(dá)成共識(shí)的條件
N 個(gè)進(jìn)程中大多數(shù)(超過一半)進(jìn)程都選定了同一個(gè)值
推導(dǎo)流程
假設(shè)存在三個(gè)進(jìn)程 p1 p2 p3,共同決定 v 的值
1.1 每個(gè)進(jìn)程只接受收到的第一個(gè)提案
場(chǎng)景 1.1.1
p1 proposal:v = a
p2 proposal: v = b
p3 proposal: 無
假設(shè)是 p1 的 proposal 優(yōu)先到達(dá) p3,p2 的 proposal 在到達(dá) p3 時(shí)會(huì)被拒絕,系統(tǒng)就 v = a 達(dá)成了共識(shí),反之如果 p2 的 proposal 優(yōu)先到達(dá),系統(tǒng)會(huì)就 v = b 達(dá)成共識(shí)。
場(chǎng)景 1.1.2
p1 proposal:v = a
p2 proposal: v = b
p3 proposal: v = c
這樣每個(gè)機(jī)器只能接受自己機(jī)器上的 proposal,對(duì)于 v 的值就永遠(yuǎn)不能達(dá)成共識(shí)了。
結(jié)論 1.1:
- 進(jìn)程必須能夠多次改寫 v 的值,否則可能永遠(yuǎn)達(dá)不成共識(shí)
- 進(jìn)程必須接受第一個(gè) proposal,否則可能永遠(yuǎn)達(dá)不成共識(shí)(系統(tǒng)只有一個(gè)提案時(shí))
1.2 每個(gè)進(jìn)程只接受 proposal_id 大的提案
根據(jù) 1.1 的結(jié)論,進(jìn)程必須接受第一個(gè) proposal, 所以需要一種拒絕策略或者修正后到達(dá)的 proposal 的 value 我們需要額外的信息作為依據(jù)來完成。
- 我們得到哪些信息呢?
提出 proposal 進(jìn)程的標(biāo)識(shí) process_id,當(dāng)前進(jìn)行到輪次 round_number(每個(gè)進(jìn)程自增) - 這些信息有什么用?
這兩個(gè)信息加在一起標(biāo)識(shí)唯一的 proposal
暫定 proposal_id = round_number + process_id - 如何更新 proposal_id?
每個(gè) process 的 proposal_id = max(proposal_id, a_proposal_id)
場(chǎng)景 1.2.1
假設(shè) p1_proposal_id > p2_proposal_id
p1 proposal:v = a
p2 proposal: v = b
p3 proposal: 無
如果 p1 proposal 先到達(dá) p3 ,p2 后到達(dá),會(huì)形成
p1 proposal:v = a
p2 proposal: v = a
p3 proposal: v = a
系統(tǒng)就 v = a 達(dá)成共識(shí)。
場(chǎng)景 1.2.2
如果 p2 proposal 先到達(dá) p3 , p1 后到達(dá),p3 會(huì)先接受 p2 proposal,形成
p1 proposal:v = a
p2 proposal: v = b
p3 proposal: v = b
系統(tǒng)就 v = b 達(dá)成共識(shí),因?yàn)?p1 proposal 也已經(jīng)發(fā)出,接著又會(huì)形成
p1 proposal:v = a
p2 proposal: v = a
p3 proposal: v = a
系統(tǒng)又就 v = a 達(dá)成了共識(shí)。
在這個(gè)策略中,有兩個(gè)值先后達(dá)成共識(shí),不滿足安全性。
結(jié)論 1.2:
按照現(xiàn)有 1.2 策略存在proposal id 小 proposal 先到達(dá),系統(tǒng)多次就不同的值達(dá)成共識(shí)的問題。從如下幾個(gè)角度思考解決此問題
- p3 可以拒絕 p2 proposal(p2 proposal 先到達(dá) p3,p2_proposal_id < p1_proposal_id )
- 限制 p1 提出的 proposal
1.3 p3 可以拒絕 p2 proposal 角度
- 發(fā)送帶有 proposal_id PreProposal,
- 接收到 PreProposal 的進(jìn)程,根據(jù) proposal_id = max(proposal_id, accept_proposal_id) 進(jìn)行更新
- 進(jìn)程發(fā)送 proposal
- 每個(gè)進(jìn)程只接受 proposal_id 大的 proposal
假設(shè) p1_proposal_id > p2_proposal_id
p1 proposal:v = a
p2 proposal: v = b
p3 proposal: 無
場(chǎng)景 1.3.1
- p1_PreProposal 攜帶 p1_proposal_id 到達(dá) p3
- P3 更新 p3_proposal_id 為 p1_proposal_id, P2 更新 p2_proposal_id 為 p1_proposal_id
- p2_PreProposal 攜帶 p2_proposal_id 到達(dá),p2_proposal_id < p1_proposal_id,被拒絕。
- p1_proposal (v = a)到達(dá) p2, p3
- 此時(shí)系統(tǒng)就 v = a 達(dá)成共識(shí)
- p1: v = a
- p2: v = a
- p3: v = a
場(chǎng)景 1.3.2
- p2_PreProposal 攜帶 p2_proposal_id 進(jìn)行廣播,到達(dá) p3
- P3 更新 p3_proposal_id 為 p2_proposal_id
- p2_proposal (v = b)到達(dá) p3,系統(tǒng)此時(shí)會(huì)就 v = b 達(dá)成共識(shí)
- p1: v = a
- p2: v = b
- p3: v = b
- p1_PreProposal 攜帶 p1_proposal_id 進(jìn)行廣播,到達(dá) p2, p3, p2_proposal_id < p1_proposal_id,p2 p3 更新 proposal_id 為 p1_proposal_id
- p1_proposal (v = a)到達(dá) p2, p3
- 此時(shí)系統(tǒng)就 v = a 達(dá)成共識(shí)
- p1: v = a
- p2: v = a
- p3: v = a
結(jié)論 1.3:
1.3 策略解決了一部分問題,但是還是依賴消息到達(dá)的先后順序。在某些條件下還是不能保證安全性。
1.4 限制 p1 提出的 proposal
現(xiàn)在已知 process_id round_number,還能得到哪些信息?
按照 1.3 的策略,我們只是更新了接受 pre_proposal 的 accept_process 的 proposal_id 為較大的 proposal_id,并沒有回復(fù)給發(fā)送 pre_propoal 的 send_process 任何消息。是不是可以把 accept_process 已經(jīng)獲得的提案的 proposal_id 和 proposal 這樣是不是限制 send_process 接下來發(fā)送的 proposal ?現(xiàn)在模擬一下流程,看看能否解決 1.3 中存在的問題。
- 發(fā)送帶有 proposal_id 的 PreProposal
- 接收到 PreProposal 的進(jìn)程,根據(jù) proposal_id = max(proposal_id, accept_proposal_id) 進(jìn)行更新,并回復(fù)當(dāng)前進(jìn)程已經(jīng)接收到的 proposal_id
- 進(jìn)程發(fā)送 proposal
- 每個(gè)進(jìn)程只接受 proposal_id 大的 proposal
假設(shè) p1_proposal_id > p2_proposal_id
p1 proposal:v = a
p2 proposal: v = b
p3 proposal: 無
場(chǎng)景 1.4.1
- p2_PreProposal 攜帶 p2_proposal_id 進(jìn)行廣播,到達(dá) p3
- P3 更新 p3_proposal_id 為 p2_proposal_id
- P3 給 P2回復(fù) (p2_proposal_id, v=NULL)
- p2_proposal (v = b)到達(dá) p3,系統(tǒng)此時(shí)會(huì)就 v = b 達(dá)成共識(shí)
- p1: v = a
- p2: v = b
- p3: v = b
- p1_PreProposal 攜帶 p1_proposal_id 進(jìn)行廣播,到達(dá) p2, p3, p2_proposal_id < p1_proposal_id,p2 p3 更新 proposal_id 為 p1_proposal_id
- P3 回復(fù) P1 (p2_proposal_id, v=b)
- P1 發(fā)現(xiàn) P3 已經(jīng)接受了 v = b,把自己的提案 v = a 修改成 v = b
- p1_proposal (v = b)到達(dá) p2, p3
- 此時(shí)系統(tǒng)還是就 v = b 達(dá)成共識(shí)
- p1: v = b
- p2: v = b
- p3: v = b
問題得到了解決。
上文所有的推導(dǎo),全部來源于三個(gè)進(jìn)程,看似問題已經(jīng)解決。但是這個(gè)流程能否一般化,應(yīng)用于 N 個(gè)進(jìn)程呢?提案數(shù)從 2 到 N 呢?
泛化推導(dǎo),
場(chǎng)景 1.5 進(jìn)程數(shù)從 3 到 N
Pi 進(jìn)程集合:提出 PreProposal-i,Proposal-i(v = a)
Qi 進(jìn)程集合:接受了 Proposal-i 的超半數(shù)進(jìn)程
Pj 進(jìn)程集合:提出 PreProposal-j,Proposal-j(v = b)
Qj 進(jìn)程集合:接受了 Proposal-j 的超半數(shù)進(jìn)程
Pk 進(jìn)程集合:Qi 和 Qj 的進(jìn)程集合交集
只要 Pk 能夠拒絕 Proposal-i 和 Proposal-j 的一個(gè)就是安全的
每個(gè) Proposal-j-id < Proposal-i-id
- Proposal-j 到達(dá)部分進(jìn)程,此時(shí)系統(tǒng)未達(dá)成共識(shí)
- PreProposal-i 到達(dá)部分進(jìn)程,此時(shí)系統(tǒng)未達(dá)成共識(shí)
- 所有接收到 PreProposal-i 的進(jìn)程回復(fù)(Proposal-j-id, v = b)或者 (NULL, NULL) 給 Pi
- Pi 接受到(Proposal-j-id,v = b),將 Proposal-i 原先的 v = a 修改成 v = b,然后進(jìn)行廣播。
- 系統(tǒng)就 v = b 達(dá)成共識(shí)。
場(chǎng)景 1.6 不同的 proposal 由 2 到 N
假設(shè) j - i = N,b - a = N
Pi Pi+1 ... Pi+N-1 Pj 每個(gè)進(jìn)程組都會(huì)提出 Proposal(v = a, a+1, .. a+N-1, b) Proposal_id 大小順序相反
Qi -> Qj 與 Pi 相對(duì)
Pk 是收到了很多不同提案的進(jìn)程的集合,但是一直沒有達(dá)成共識(shí)。
- Proposal-i+1 Proposal-i+2 到達(dá) Pk,系統(tǒng)并沒有達(dá)成共識(shí)。
- PreProposal-j 發(fā)出到達(dá)部分進(jìn)程
- 接收到 PreProposal-j 的進(jìn)程選擇 [(Proposal-i+1-id, v = a + 1), (Proposal-i+2-id, v = a + 2)] 其中的一個(gè)或者兩個(gè)一起回復(fù)給 Pj
- Pj 應(yīng)該選擇哪個(gè) v 值修改自己的 proposal 呢
- 回顧前邊的邏輯,每個(gè)進(jìn)程會(huì)拒絕 Proposal-id 較小的提案,Proposal-i+1-id > Proposal-i+2-id
- Proposal-i+1-id 相比 Proposal-i+2-id 的提案肯定先到 Pk 的,系統(tǒng)還有一部分進(jìn)程沒有接收到 (Proposal-i+1-id, v = a + 1),沒有就 (Proposal-i+1-id, v = a + 1) 形成共識(shí)
- 假設(shè) Pj 選擇 proposal_id 較小的 proposal ,那么會(huì)選擇 (Proposal-i+2-id, v = a + 2) ,在 Pj 發(fā)出 (Proposal-j, v = a + 2) 之前,沒有收到 (Proposal-i+1-id, v = a + 1) 的進(jìn)程可能恰好收到了,系統(tǒng)就 v = a + 1 達(dá)成了共識(shí)。此后(Proposal-j, v = a + 2) 達(dá)到了, 系統(tǒng)又 v = a + 2 達(dá)成的共識(shí)。系統(tǒng)兩次達(dá)成共識(shí),存在問題。
- 假設(shè) Pj 選擇 proposal_id 較大的 proposal,那么會(huì)選擇 (Proposal-i+1-id, v = a + 1) ,在 Pj 發(fā)出 (Proposal-j, v = a + 1) 之前,沒有收到 (Proposal-i+1-id, v = a + 1) 的進(jìn)程可能恰好收到了,系統(tǒng)就 v = a + 1 達(dá)成了共識(shí)。此后(Proposal-j, v = a + 2) 達(dá)到了,還是 v = a + 1。不存在問題。
- 系統(tǒng)選擇 proposal_id 較大的修改依據(jù)
- Pj 選擇 proposal_id 較大的 proposal,修改 v = a + 1,并發(fā)出 (Proposal-j, v = a + 2)
- 系統(tǒng)就 v = a + 2 達(dá)成共識(shí)
不能覆蓋的場(chǎng)景
如果每次 proposal 被接受之前,先接受了攜帶較大 proposal-id 的 PreProposal,這樣每次都會(huì)拒絕即將成功的達(dá)成共識(shí)的 proposal 系統(tǒng)每次都不會(huì)達(dá)成共識(shí)。這個(gè)場(chǎng)景可以通過不斷重試解決。
paxos
Proposer: 發(fā)起提案的進(jìn)程
Acceptor: 接受題提案的進(jìn)程
一個(gè)進(jìn)程可能充當(dāng)多個(gè)角色
Phase 1:
- Proposer 選擇一個(gè)提案編號(hào) n,然后向 Acceptors 的某個(gè) majority 集合的成員發(fā)送編號(hào)為 n 的prepare請(qǐng)求。
- 如果一個(gè)Acceptor收到一個(gè)編號(hào)為 n 的prepare請(qǐng)求,且 n 大于它已經(jīng)響應(yīng)的所有prepare請(qǐng)求的編號(hào),那么它就會(huì)保證不會(huì)再通過(accept)任何編號(hào)小于 n 的提案,同時(shí)將它已經(jīng)通過的最大編號(hào)的提案(如果存在的話)作為響應(yīng)。
Phase 2
- 如果 Proposer 收到來自半數(shù)以上的 Acceptor 對(duì)于它的 prepare 請(qǐng)求(編號(hào)為 n)的響應(yīng),那么它就會(huì)發(fā)送一個(gè)針對(duì)編號(hào)為 n ,value 值為 v 的提案的 accept 請(qǐng)求給 Acceptors,在這里 v 是收到的響應(yīng)中編號(hào)最大的提案的值,如果響應(yīng)中不包含提案,那么它就是任意值。
- 如果 Acceptor 收到一個(gè)針對(duì)編號(hào) n 的提案的accept請(qǐng)求,只要它還未對(duì)編號(hào)大于 n 的 prepare 請(qǐng)求作出響應(yīng),它就可以通過這個(gè)提案。