0 導讀
之前的文章中,我們介紹過分散式事務的基礎知識,也瞭解了分散式場景下常見一致性問題和解決方案,對分散式鎖和CAS模式有一定的瞭解,有興趣的同學可以透過下面連結到作者的兩篇相關文章。
五種分散式事務解決方案(圖文總結)
高併發下的資料一致性保障(圖文全面總結)
1 介紹
本文聚焦高併發場景下分散式一致性演算法的分析和討論
分散式場景下困擾我們的3個核心問題(CAP):一致性、可用性、分割槽容錯性。
1、一致性(Consistency): 無論服務如何拆分,所有例項節點同一時間看到是相同的資料
2、可用性(Availability): 不管是否成功,確保每一個請求都能接收到響應
3、分割槽容錯性(Partition Tolerance): 系統任意分割槽後,在網路故障時,仍能操作
而我們最為關注的是如何在高併發下保障 Data Consistency(資料一致性),因為在很多核心金融業務場景(如 支付、下單、跨行轉賬)中,為了避免資金問題,是需要強一致性結果的。
而分散式一致性演算法就是保障 Data Consistency的強大利刃,它的目標是確保分散式系統中多個節點在讀取或修改同一份資料時,產生相同結果的關鍵機制。這些演算法對於保證分散式系統的一致性和可靠性至關重要。
常用的分散式演算法:
- Paxos演算法
- Raft演算法
- ZAB(ZooKeeper Atomic Broadcast)演算法
2 主流分散式演算法
2.1 Paxos演算法
Paxos演算法是一種用於分散式系統中保障一致性的演算法,由Leslie Lamport於1990年提出,被廣泛應用於分散式系統中的一致性問題,如分散式資料庫、分散式儲存系統等。
該演算法的主要目標是在一個由多個節點組成的分散式系統中,協調某個資料值並達成一致性,典型的少數服從多數的案例。
2.1.1 基本概念
1. 提案: 由提案號(id)和提案內容(value)組成,其中id主要用於實現Paxos演算法,而value對應在實際的分散式系統中為所需要修改資料的命令 或者 log資訊。
2. 角色: Paxos演算法中抽象出來的概念,對應著實際分散式環境中的不同分工。主要角色包括提議者(Proposer)、批准者(Acceptor)和學習者(Learner)。
- 提議者負責提出值的提案
- 接受者負責接受提案並投票
- 學習者負責學習已經達成一致的值
Proposer 提案者
提案者負責提出提案 (Proposal),Proposal資訊包括提案編號 (Proposal ID) 和提議的值 (Value)。提案的value,可以是任何行為或者操作,比如傳統轉賬場景,將使用者的賬號餘額從0改為100,Paxos 協議統一抽象為value。 Proposer可以有多個,不同的Proposer可以提出不同的甚至互斥的value,比如提案者A消費(將變數Money-100),提案者B也消費(將變數Money-200),但對同一輪Paxose而言,最多隻有一個value可以被批准,否則就亂套了。
Acceptor 批准者
Acceptor 從含義上來說就是除了當前Proposer以外的其他機器,他們之間完全平等和獨立,Proposer需要爭取超過半數(N/2+1)的 Acceptor 批准後,其提案才能透過,它倡導的“value”操作才能被所有機器(包括Proposer、Acceptor、Learner)所接受。
Learner 學習者
Learner 不參與選舉,而是學習被批准的 value,在Paxos中,Learner主要參與相關的狀態機同步流程。這裡Leaner的流程就參考了Quorum議會機制,某個value需要獲得超過半數的Acceptor 批准,才能真正被Learner學習到。
2.1.2 演算法流程
1. 準備階段(Prepare階段):提議者(Proposer)向所有Acceptor節點發起Prepare請求,攜帶全域性唯一且遞增的提案編號N,要求它們告訴提議者已經接受的最高提議號。如果接受者接受了輪次小於當前輪次的提案,那麼它會更新自己的狀態,拒絕當前輪次的提案。
2. 承諾階段(Promise階段) :Acceptor節點接收到prepare請求後,會檢查該請求的提議號是否比它已經接受的提議號更高。如果是,那麼節點會更新自己的狀態,承諾不再接受輪次小於當前輪次的提案。
Acceptor收到Prepare請求後,有兩種情況:
- 如果Acceptor首次接收Prepare請求, 設定MaxN=N, 同時響應ok
- 果Acceptor不是首次接收Prepare請求,則:
- 若請求過來的提案編號N小於等於上次持久化的提案編號ResN,則不響應或者響應error。
- 若請求過來的提案編號N大於上次持久化的提案編號MaxN, 則更新MaxN=N,同時給出正確的響應。
3. 承諾響應階段(Acknowledge階段) :在這個階段,接受者會檢查自己是否接受了當前提案。如果是,那麼接受者會返回一個承諾響應,告訴提議者當前提案已經被接受。
4. 提議的接受與決策 :當Acceptor節點接收到一個提議請求時,它會檢查該提議的值是否比它已經接受的值更高。如果是,那麼它會接受該提議,並向其他節點傳送接受訊息。當一個提議被大多數節點接受後,該提議就成為了決策,並被所有節點執行。
Proposer 獲得 Accept 回覆的資訊之後,做如下判斷:
- 回覆數量 > Acceptor 數量的1/2時,代表提交 value 成功,傳送廣播給所有的 Proposer、Learner,通知它們已提交的 value。
- 回覆數量 <= Acceptor 數量的1/2時,則重新開始,更新生成更大的提案號,跳轉到準備階段執行。
- 收到響應error時,同樣更新生成更大的提案號,轉到準備階段執行。
5. 學習階段(Learn階段) :學習者會向所有接受者傳送一個學習請求,接受者會返回已經接受的最大提案,使學習者能夠學習到已經達成一致的值。
2.1.3 應用
Paxos演算法具有高度容錯特性,可以在某個節點當機、網路異常、訊息延遲等問題的情況下,快速且正確地在叢集內部對某個資料達成一致。所以在很多業務場景中得到應用。比如:
- Zookeeper使用一個類Multi-Paxos的共識演算法作為底層儲存協同的機制。
- Google公司在其分散式鎖中應用了Multi-Paxos演算法。
2.2 Raft演算法
2.2.1 基本概念
Raft 演算法是一致性算的一種,用來解決分散式一致性問題。它提供了一種在計算系統叢集中分佈狀態機的通用方法,確保叢集中的每個節點都同意一系列相同的狀態轉換。
其主要目標是解決分散式系統中的領導者選舉、日誌複製和安全性等關鍵問題。
2.2.2 領導者選舉與超時機制
在Raft演算法中,伺服器可以處於三種狀態:領導者(leader)、跟隨者(follower)和候選者(candidate)。正常情況下,叢集中只包含一個 leader ,其餘伺服器都是 follower 。
跟隨者透過投票選出領導者,只有得到“大多數”跟隨者投票的伺服器能成為領導者;領導者負責將命令同步給跟隨者,只有被“大多數”跟隨者確認的命令才能提交。
1. 跟隨者(Follower)
Fllower是所有節點的初始狀態,內部都會有一個隨機超時時間。這個超時時間,規定了在倒數計時結束後仍然收不到Leader的心跳,Follower就會轉變為Candidate。
2. 候選者(candidate)
Follower在轉變為Candidate後,超時時間重置,倒數計時結束時就會向其他節點提名自己的實,拉取選票。
如果能獲得半數以上(1/2以上,包含自己投給自己的)的選票,則當選為Leader,這個過程就叫做Leader選舉。
所以節點最好是單數,避免極端情況下出現一個叢集選舉出兩個Leader的腦裂問題。
3 .領導者(leader)
Raft叢集透過Leader與客戶端進行互動,Leader不斷處理寫請求與傳送心跳給Follower,Follower在收到Leader的心跳後,其超時時間會重置,即重新開始倒數計時。
正常工作期間只有 Leader 和 Follower,且Leader至多隻能有一個。
角色狀態轉換過程
2.3 ZAB(ZooKeeper Atomic Broadcast)演算法
2.3.1 基本概念
ZAB(Zookeeper Atomic Broadcast)是Zookeeper原子訊息廣播協議,是Zookeeper保證資料一致性的核心演算法。該演算法借鑑了Paxos演算法,但又不像Paxos那樣是一種通用的分散式一致性演算法,而是特別為Zookeeper設計的支援崩潰恢復的原子廣播協議。
在Zookeeper中,主要依賴ZAB協議來實現資料一致性。基於該協議,Zookeeper實現了一種主備模型(即Leader和Follower模型)的系統架構,保證叢集中各個副本之間資料的一致性。透過一臺主程序(Leader)負責處理外部的寫事務請求,然後將資料同步到其他Follower節點,如果超過半數成功ACK,則主程序執行 Commit操作。
2.3.2 廣播流程
ZAB 協議的訊息廣播過程使用的是一個原子廣播協議,類似一個 二階段(2PC) 提交過程。
對於客戶端傳送的寫請求,全部由 Leader 接收,Leader 將請求封裝成一個事務 Proposal,將其傳送給所有 Follwer ,
然後,根據所有 Follwer 的反饋,如果超過半數成功響應,則執行 Commit 操作(先提交自己,再傳送 Commit 給所有 Follwer)
3 總結
分散式一致性演算法是確保分散式系統中多個節點在讀取或修改同一份資料時,產生相同結果的關鍵機制。這些演算法對於保證分散式系統的一致性和可靠性至關重要。
目前常見以下是一些常用的分散式一致性演算法:
- Paxos演算法:由Lamport宗師提出,是一種基於訊息傳遞的分散式一致性演算法。它旨在解決在一個可能發生故障的分散式系統中,如何快速正確地在叢集內對某個值達成一致,並保證整個系統的一致性。
- Raft演算法:一種相對易於理解的分散式一致性演算法,它將一致性問題的複雜性分解為若干個相對獨立的子問題。Raft透過選舉和日誌複製的方式確保資料的一致性。
- ZAB(ZooKeeper Atomic Broadcast)演算法:是ZooKeeper中使用的原子廣播協議,用於實現分散式系統中的狀態同步。ZAB協議包括恢復模式和廣播模式,確保ZooKeeper叢集中的各個節點能夠保持資料的一致性。
此外,還有其他分散式一致性演算法,如Gossip協議等,這些演算法在不同的分散式系統場景中有各自的應用和優勢。
在選擇分散式一致性演算法時,需要考慮系統的規模、節點的數量、通訊開銷、資料一致性要求以及容錯性等因素。不同的演算法可能適用於不同的場景,因此需要根據具體情況進行選擇和調整。