一、Paxos算法
世界上只有一種一致性算法,就是 Paxos,其它的算法都是殘次品,但Paxos非常複雜難懂。
算法原理參考:Paxos的通俗解釋 Paxos共識算法詳解
算法例子參考:如何淺顯易懂地解說 Paxos 的算法?
Paxos算法的核心問題是:解決分佈式系統的一致性的問題,所有問題均圍繞着在分佈式環境達成一致性而展開討論的。
預備知識
術語:
- proposer:提案者,它可以提出一個提案。
- acceptor:提案的受理者,有權決定是否它本身是否批准該提案。
- learner:不參與Paxos提案選定的過程,只在提案被選定時,知道提案結果的角色。
- proposal:由Proposer 提出的提案,每個提案由編號及value組成,如[m, value],提案的編號必須是全局唯一,value即代表了提案本身的內容。
- choose:提案被選定,當有半數以上Acceptor批准該提案時,就認爲該提案被選定了。
提案編號:
有專門的編號生成算法,只需要知道它是全局唯一且遞增的就行了,就是說越新的提案,編號越大。
通信條件:
- 系統所有消息均存在延遲、丟失、重複的可能,系統也可以隨時會重啓。
- 系統所有的消息不存篡改的問題,也即不存在拜占庭的問題。
算法過程
跳過複雜的推理過程,直接給出算法過程。
Learner不參與投票過程,爲了簡化描述,我們直接忽略掉這個角色。
算法分爲兩個階段執行。
階段1.
- proposer:選擇一個提案編號Mn,向超過半數的acceptor發送編號爲Mn的prepare請求。
- acceptor:如果接收到編號爲Mn 的prepare請求,並且Mn大於它已經迴應的任何prepare請求,它就回復Promise響應,返回已經批准的編號最高的提案的value(如果有的話),並承諾不再批准任何編號小於Mn的提案。
階段2.
- proposer :
- 如果收到了多數acceptor對prepare請求Mn的迴應,它就向這些Acceptor發送提案[Mn, Mv]的accept請求,其中Mn的值爲:
- 響應帶回了其他的已批准的提案,所有prepare請求響應中編號最大的已批准提案的value(相當於放棄自己的提案,變成復讀機)。
- 響應沒有帶回其他的已批准的提案:proposer 自己選擇的value(相當於還沒有其他提案被批准過,該proposer獲得first blood)。
- 沒有收到多數acceptor對prepare請求Mn的迴應:回到第一步重新發起提案。
- 如果收到了多數acceptor對prepare請求Mn的迴應,它就向這些Acceptor發送提案[Mn, Mv]的accept請求,其中Mn的值爲:
- acceptor:如果收到了提案[Mn, Mv]的accept請求,它就回復accepted響應,批准該提案,除非它已經迴應了一個編號大於Mn的提案。
算法過程圖示
可見Acceptor需要持久化存儲minProposal、acceptedProposal、acceptedValue這3個值。
proposer 可以提出多個提案,只要它遵循上面的算法。它可以在任何時刻放棄一個提案。(這不會破壞正確性,即使在提案被放棄後提案的請求或者回應消息纔到達目標)如果其它的proposer 已經開始提出更高編號的提案,那麼最好能放棄當前的提案。
二、Raft算法
Raft 也是一個一致性算法,且比起Paxos更容易理解。就是說Paxos雖然在學術界是最強的,但是難理解、難實現,所以工業界廣泛使用的還是Raft算法。
Raft主要有兩個模塊:領導人選舉和日誌複製。
領導人選舉
Raft 通過選舉一個領導人,然後給予他全部的管理複製日誌的責任來實現一致性。
每個節點可以在三個身份之間切換:Leader、candidate、follower。
剛開始時所有節點都是follower,這個時候需要選舉一個 leader,所有人都變成candidate,直到有人成功當選 leader,這些落選的candidate又變回follower。角色輪換圖如下:
其中,leader也有可能會宕機,就需要引發新的選舉,所以整個集羣在選舉和正常運行之間切換,具體如下圖:
可以注意到, 上圖中的 term 3 選舉之後沒有跟着正常運行階段,這是因爲當一次選舉失敗(比如正巧每個節點都投了自己)後,就需要再重新選舉,每個節點會在一個隨機的時間裏重新投票,這樣就能保證不衝突了。所以,當 term 3 選舉失敗,等了幾十毫秒,執行 term 4 選舉,併成功選舉出leader。
接着,leader週期性的向所有follower發送心跳包來維持自己的權威。如果一個follower在一段時間裏沒有接收到任何消息,也就是選舉超時,那麼他就會認爲系統中沒有可用的leader或者leader宕機,並且發起選舉以選出新的leader。
要開始一次選舉過程,follower先要增加自己的當前任期號並且轉換到candidate狀態。然後請求其他服務器爲自己投票。
規則:
- 每一個 server 最多在一個任期內投出一張選票(有任期號約束),先到先得。
- 要求最多隻能有一個人贏得選票。
- 一旦成功,立即成爲領導人,然後廣播所有服務器停止投票阻止新得領導產生。
可能會產生 3 種結果:
- 自己成功當選
- 其他人成爲領導者
- 所有人票數相同,沒有任何一個人成爲領導者
遇到第三種情況而僵住時,Raft 通過使用隨機選舉超時時間(例如 150 - 300 毫秒)的方法將服務器打散投票。每個候選人在僵住的時候會隨機從一個時間開始重新選舉。
日誌複製
一個leader被選舉出來後,他就開始爲客戶端提供服務。
客戶端發送日誌給leader,隨後leader將日誌複製到他的follower上。如果follower故障,leader將會嘗試重試,直到所有的follower都成功存儲了所有日誌。
下圖表示了當一個客戶端發送一個日誌給leader,隨後leader複製給follower的整個過程。
4 個步驟:
- 客戶端提交數據給leader
- leader複製數據給所有follower
- follower回覆
確認接收
- leader回覆客戶端和所有follower
確認提交
。
直到第4步驟,整個事務纔會達成。中間任何一個步驟發生故障,事務都會中止,因此故障不會影響到日誌一致性。
與其他算法的區別
- 2PC 和 3PC都只有一個協調者,宕機之後會使階段提交無法進行(2PC的參與者會阻塞,3PC的參與者可以繼續本地提交)。
- Paxos有多個accepter,審批proposer的提案。
- Raft只有一個leader,如果leader宕機,可以重新選舉一個leader出來繼續工作。