前言
世界上只有一種一致性演算法,就是 Paxos
。出自一位 Google
大神之口。Paxos
也是出名的 晦澀難懂,推理過程極其複雜。
Paxos
有點類似之前說的 2PC
,3PC
,但是解決了這兩種演算法各種硬傷。該演算法在很多大廠都得到了工程實踐,比如阿里的 OceanBase
的 分散式資料庫,底層就是使用的 Paxos
演算法。再比如 Google
的 chubby
分散式鎖 也是用的這個演算法。可見該演算法在分散式系統中的地位,甚至於,Paxos
就是 分散式一致性 的代名詞。
正文
1. Paxos演算法是什麼
Paxos
演算法是 基於訊息傳遞 且具有 高效容錯特性 的一致性演算法,目前公認的解決 分散式一致性問題 最有效的演算法之一.
2. Paxos演算法產生背景
2.1. 拜占庭將軍問題
拜占庭是古代東羅馬帝國的首都,由於地域寬廣,守衛邊境的多個將軍(系統中的多個節點)需要通過信使來傳遞訊息,達成某些一致的決定。但由於信使中可能存在叛徒(系統中節點出錯),這些叛徒將努力向不同的將軍傳送不同的訊息,試圖會干擾一致性的達成。
2.2. Paxos演算法由來
故事背景是古希臘 Paxos
島上的多個法官在一個大廳內對一個議案進行表決,如何達成統一的結果。他們之間通過服務人員來傳遞紙條,但法官可能離開或進入大廳,服務人員可能偷懶去睡覺。
2.3 產生背景
在常見的 分散式系統 中,總會發生 節點當機 或 網路異常 (包括訊息的 重複、丟失、延遲、亂序、網路分割槽) 等情況。
Paxos
演算法主要就是解決如何在一個 發生如上故障 的分散式系統中,快速正確的在叢集內 對某個值達成一致,並且保證 整個系統的一致性。
3. 演算法詳解
3.1 角色 & 提案
提案 (Proposal)
注意:提案的範圍>value.後面會講到,[提案=編號+Value].也可表示為[M,V]. 以下描述中暫定: 提案=P,Value=V.
角色
-
Proposer :
Proposer
可以 提出提案 (Proposal
)。 -
Accecptor :
Acceptor
可以 接受提案。一旦接受提案,提案 裡面的value
值就被選定了。 -
Learner :
Acceptor
告訴Learner
哪個提案被選定了,那麼Learner
就學習這個被選擇的value
。
在具體的實現中,一個程式即可能是Proposer,也可能是Acceptor,也可能是Learner。
3.2. 問題描述
Paxos
演算法的核心是 一致性。所以將從一致性問題的描述來講解該演算法怎麼解決實際問題。
3.2.1. 一致性演算法的前置條件
- 在被提出的
P
中,只有一個V
被選中。 - 如果沒有
P
被提出,就沒有V
被選中。 - 在
P
被選定後,程式都可以學習被選中的P
。
3.2.2. 不同角色通過傳送訊息進行通訊
-
每個角色以任意的速度執行,可能因出錯而停止,也可能會重啟。一個
value
被選定後,所有的角色可能失敗然後重啟,除非那些失敗後重啟的角色能記錄某些資訊,否則等他們重啟後無法確定被選定的值。 -
訊息在傳遞過程中可能出現 任意時長的延遲,可能會 重複,也可能 丟失,但是訊息不會被 損壞。
3.3. 推導過程
3.3.1. 只有一個Acceptor
一個 Acceptor
接受一個 P
,那麼只有一個 V
被選定。
問題:如果這個 Acceptor 當機,那麼整個系統服務不可用。
3.3.2. 多個Acceptor
問題:如何在多 Proposer 和多 Acceptor 情況下,選定一個 value?
講解步驟分兩階段:約定 P1
和 約定 P2
。
3.3.2.1. 約定P1
P1 :一個 Acceptor 必須接受一個它收到的第一個 P。
如果每個 Proposer 會產生不同的 P,那麼多個 Proposer 必定產生多個 P,發給多個 Acceptor。根據 約定 P1
,Acceptor
分別接受到 P
,就會導致不同的 V
被選定,如下圖所示:
如上圖所示,P1
會產生的問題: v1
、v2
、v3
都沒有被選定,因為他們只有被一個 Acceptor
接受。
對於上述問題,我們需要一個額外的約定:
P1a : 一個提案 P 被選定,需要被半數以上 Acceptor 接受.
對於 P1a
,其實就意味著 一個Acceptor必須接受不止一個提案。
顯然,這與 P1
相矛盾,所以需要重新設計提案。原來的設計是: [提案P = value]
,現在重新設計 [提案P = 提案編號 + value]
,可表示為 [M,V]
。
新問題:多提案被選定,如何保證被選定的提案 P 具有相同的value?
3.3.2.2. 約定P2
P2 : 如果提案 P[M0,V0] 被選定了,那麼所有比 M0 編號更高的,且被選定的 P,其 value 的值也是 V0。
對於 P2
中的 “被選定”:一個提案要被選定,首先至少要被一個 Acceptor
批准。因此,可以理解 P2
為:
P2a : 如果提案 P[M0,V0] 被選定了,那麼所有比 M0 編號更高的,且 [被Acceptor批准] 的P,其 value 值也是 V0。
只要滿足 P2a
,就能滿足 P2
。多提案被選擇 的問題解決了,但是由於 網路不穩定 或者 當機 的原因(不可避免),會產生新問題:
假設有 5
個 Acceptor
。Proposer2
提出 [M1,V1]
的提案,Acceptor2~5
(半數以上)均接受了該提案,於是對於 Acceptor2~5
和 Proposer2
來講,它們都認為 V1
被選定。Acceptor1
剛剛從 當機狀態 恢復過來(之前 Acceptor1
沒有收到過任何提案),此時 Proposer1
向 Acceptor1
傳送了 [M2,V2]
的提案 (V2≠V1且M2>M1)。對於 Acceptor1
來講,這是它收到的 第一個提案。根據 P1
(一個 Acceptor
必須接受它收到的 第一個提案),Acceptor1
必須接受該提案。同時 Acceptor1
認為 V2
被選定。
這就出現了兩個問題:
-
Acceptor1
認為V2
被選定,Acceptor2~5
和Proposer2
認為V1
被選定。出現了不一致。 -
V1
被選定了,但是 編號更高 的被Acceptor1
接受的提案[M2,V2]
的value
為V2
,且 V2≠V1。這就跟P2a
(如果某個value
為v
的提案被選定了,那麼每個 編號更高 的被Acceptor
接受的提案的value
必須也是v
)矛盾了。
基於以上問題,所有就有了 P2b
:
P2b : 如果 P[M0,V0] 被選定後,任何 Proposer 產生的 P,其值也是 V0。
對於 P2b
中的描述,怎樣保證 任何Proposer產生的P,其值也是V0 ?只要滿足 P2c
即可:
P2c: 對於任意的 M、V,如果 [M,V] 被提出,那麼存在一個半數以上的 Acceptor 組成的組合 S,滿足以下兩個條件中的任何一個: ① S 中沒有一個接受過編號小於 M 的提案。 ② S 中的 Acceptor 接受過的最大編號的提案的 value 為 V。
推導完畢。。。
3.4. 演算法流程
3.4.1. Proposer提出提案
總體思路如下:
(一). 學習階段:Prepare請求
Proposer
選擇一個新的提案 P[MN,?]
向 Acceptor
集合 S
(數目在半數以上)傳送請求,要求 S
中的每一個 Acceptor
做出如下響應:
-
如果
Acceptor
沒有接受過提案,則向Proposer
保證 不再接受編號小於N的提案。 -
如果
Acceptor
接受過請求,則向Proposer
返回 已經接受過的編號小於N的編號最大的提案。
(二). 接受階段:Acceptor請求
-
如果
Proposer
收到 半數以上 的Acceptor
響應,則 生成編號為N
,value
為V
的提案[MN,V]
,V
為所有響應中 編號最大 的提案的value
。 -
如果
Proposer
收到的響應中 沒有提案,那麼value
由Proposer
自己生成,生成後將此提案發給S
,並期望Acceptor
能接受此提案。
3.4.2. Acceptor接受提案
Acceptor
可以忽略任何請求(包括 Prepare
請求和 Accept
請求)而不用擔心破壞 演算法的安全性。因此,我們這裡要討論的是什麼時候 Acceptor
可以響應一個請求。
對 Acceptor
接受提案給出如下約束:
P1b:一個 Acceptor 只要尚未響應過任何編號大於 N 的 Prepare 請求,那麼就可以接受這個編號為 N 的提案。
如果 Acceptor
收到一個編號為 N
的 Prepare
請求,在此之前它已經 響應過 編號大於 N
的 Prepare
請求。根據 P1b
,該 Acceptor
不可能接受編號為 N
的提案。因此,該 Acceptor
可以 忽略 編號為 N
的 Prepare
請求。當然,也可以回覆一個 error
,讓 Proposer
儘早知道自己的提案 不會被接受。
因此,一個 Acceptor
只需記住:
- 已接受的編號最大的提案;
- 已響應的請求的最大編號。
4. Paxos演算法描述
5. Learner學習提案
Learner
學習(獲取)被選定的 value
有如下三種方案:
6. 如何保證Paxos演算法的活性
小結
Paxos
在 節點當機恢復、訊息無序或丟失、網路分化 的場景下能保證 資料的一致性。而 Paxos
的描述側重於 理論,在實際專案應用中,處理了 N
多實際細節後,可能已經變成了另外一種演算法,這時候正確性已經無法得到理論的保證。
要證明分散式一致性演算法的正確性通常比實現演算法還困難。所以很多系統實際中使用的都是以 Paxos
理論 為基礎而 衍生 出來的變種和簡化版。例如 Google
的 Chubby
、MegaStore
、Spanner
等系統,ZooKeeper
的 ZAB
協議,還有更加容易理解的 Raft
協議。
大部分系統都是靠在實踐中執行很長一段時間,經過驗證發現系統已可以基本執行,沒有發現大的問題才能上生產環境。
相關連結
- 分散式理論(一) - CAP定理
- 分散式理論(二) - BASE理論
- 分散式理論(三) - 2PC協議
- 分散式理論(四) - 3PC協議
- 分散式理論(五) - 一致性演算法Paxos
- 分散式理論(六) - 一致性協議Raft
歡迎關注公眾號: 零壹技術棧
本帳號將持續分享後端技術乾貨,包括虛擬機器基礎,多執行緒程式設計,高效能框架,非同步、快取和訊息中介軟體,分散式和微服務,架構學習和進階等學習資料和文章。