一致性協議-Paxos,ZAB,Raft 總結

參考資料:

分佈式一致性算法——Paxos原理與推導過程

百度開源 / braft

Raft 一致性協議完整解析

Paxos,Raft,ZAB的差異對比

前言

用於在多數據備份的分佈式系統中,因機器宕機或網絡異常(包括消息的延遲、丟失、重複、亂序,還有網絡分區)等情況產生各個節點中的數據不一致。爲了各個備份數據在最終都能與集羣保持同步,擁有統一共識,所需遵守的一套協議。

一、Paxos協議

Paxos協議相對基礎,也是其他協議的基礎,他的條件限制沒有ZAB和RAFT那麼多,僅僅想要保證的是通過Paxos協議,就算髮生了數據分歧,也只有一個值被選定,即對於節點來說如果選定了某個數據,不存在其他節點選定另一個數據,只有尚未選定和選定同一個值的情況,可以保證分佈式系統中數據的最終一致性。

角色

  • 提出者(Proposer) 提出提案 想要選定某一提案的角色 對於proposer來說,當收到一半的acceptor接受提案,即認爲提案被選定。
  • 接受者(Acceptor) 接受提案 判斷是否接收提案的角色,當接受某提案之後,認爲提案被選定。
  • 學習者(Learners) 學習提案 提案若被選定,學習者即可以學習到提案。收到acceptor選定某提案請求學習之後,認爲提案被選定。

注:上面三種角色是邏輯上的概念,並沒有規定說不能是同一進程,只是擁有不同的角色。

提案的提出過程

第一步:提出者向過半接受者發prepare請求

提出者爲該數據的提案指定一個編號N ,編號N需要保證是該數據維度全局唯一併且自增的,發送給接受者。

第二步:接受者忽略/拒絕prepare請求或響應prepare請求

接受者判斷是否接受過比N大的提案,如果有,則接受者會忽略或拒絕此次prepare,拒絕更好,可以讓提案發起者更早知道自己的提案不會被該接受者接受。 如果沒有接受過比N大的提案,但接受過比N小的提案,則將接受過的最大提案號和值(M,V)返回給提出者,如果從沒接受過提案,則需要承諾不再接受任何編號比N小的提案。

第三步:提出者收到過半接受者的響應,然後向過半接受者發出Accept請求

接受者收到各種響應,如果有針對該數據的提案已經被某些接受者接受,那麼從中選出一個提案號最大的,作爲此次accept請求的值發送給接受者,如果沒有則提出者可以自行選定值然後發accept請求。

第四步:學習者學習被選定的value

acceptor接受了某個值之後,將接受的值轉發給學習者,學習者將學習到該提案。

活鎖問題

借用一張圖,上面圖示就是活鎖問題,當兩個proposer並行的想要提交某一提案的時候,可能進入無限循環。

優化

Multi-Paxos 是Basic-Paxos的優化版本。區別是:

1.改變第一階段
  • 發起提議只有一個leader,leader選舉用Basic Paxos協議產生,產生leader後接下來的提案提交只需要進行第二階段accept請求,不用每次提議都經過第一階段。
  • 當多個自認爲leader的節點(網絡分區的情況)同時發起提議退化爲Basic Paxos協議
2.解決活鎖問題

因爲杜絕了多個proposer同時提交提案。

二、ZAB協議

ZAB是Zookeeper的分佈式一致性協議,zookeeper通過ZAB,進行消息廣播和崩潰恢復,保證各節點數據的最終一致性。

在zookeeper中,寫請求由leader處理,讀請求可以由follower處理。

注:因爲是最終一致性,所以zookeeper讀請求存在不能及時讀到最新數據的情況,但也保證讀寫一致性,客戶端能保證自己寫的數據,自己能看到(通過轉發讀請求進行處理)。

思考:爲什麼說Zookeeper爲CP? 是相對而言來說的,比如euraka是AP,並不是說euraka並沒有實現一致性,只是euraka實現的一致性比zookeeper更弱而已,euraka集羣也是實現最終一致性的。而zookeeper更強,保證了客戶端提交的請求,都順序的被整個集羣處理。其中重要的區別是zookeeper基於ZAB協議若處於故障恢復階段(比如網絡分區,leader宕機,網絡中斷),此時會重新選舉leader並進行數據同步,集羣服務將不可用,而Euraka沒有Leader概念,整個集羣數據一致性是比較數據的時間戳,點對點複製,所以可用性更高。

進程狀態

  • looking 領導者還沒誕生的情況
  • Following 跟隨者的狀態
  • Leading 領導者的狀態

名詞解釋

  • epoch 標明leader的版本,每次leader變更都會進行提升
  • Zxid 事務id,高三十二位爲epoch編號,低三十二位是客戶端事務的簡單遞增數,每次一個新leader當選,會從新leader中取出最新的Zxid然後讀出epoch值,然後加1,低三十二位則重新計數。

每個節點持久化的數據

  • history:當前節點接收到事務提議的 log
  • acceptedEpoch:follower 已經接受的 leader 更改epoch的 NEWEPOCH 提議。
  • currentEpoch:當前所處的epoch
  • lastZxid:history 中最近接收到的提議的 zxid (最大的)

協議流程

1.領導選舉(Leader election)

協議並沒有規定詳細的選舉算法,但在實現中使用的 Fast Leader Election(FLE) 選lastZxid最大的。

2.發現(discovery)

  • 由上一步得到一個準leader,準leader與其他節點建立連接,發送自己的epoch和lastZxid
  • 其他節點回復currentEpoch(cepoch),以及提議集合。(思考,爲什麼不是lastZxid而是提議集合,這裏存疑?)
  • 準leader得到所有回覆中的epoch,包括自己,然後比對所有的epoch,用最大的epoch+1通知其他節點更新currentEpoch。

3.同步(sync)

上面準leader在發現的時候收到了其他節點的提議集合,可以判斷最新的提議集合,準leader將用最新的提議集合和其他節點進行同步,當過半節點都同步完成的時候,準leader才正式成爲leader,follower 只會接收 zxid 比自己的 lastZxid 大的提議。

4.廣播(Broadcast)

leader將client發過來的請求生成一個事務proposal,然後發送給Follower,多數Follower應答之後,Leader再發送Commit給全部的Follower讓其進行提交。

協議實現(與協議流程相區別)

1.Fast Leader Election 快速選舉階段

標準:

  • 選epoch最大的
  • epoch相等,選 zxid 最大的
  • epoch和zxid都相等,選擇server id最大的(就是我們配置zoo.cfg中的myid)

先投票給自己,當接收其他節點的選票時,會根據上面的標準更改自己的選票並重新發送選票給其他節點,當有一個節點的得票超過半數,該節點會設置自己的狀態爲 leading,其他節點會設置自己的狀態爲 following。

2.Recovery Phase 數據恢復階段

相當於合併了協議流程中的發現和同步,因爲經過FLE之後選舉出來的準leader就是擁有最新提議歷史(lastZxid最大)的節點。 fllower發送自己的lastZxid給leader,leader根據自己的lastZxid發送三種命令給fllower,使得fllower與leader的lastZxid保持一致 三種策略:

  • SNAP 快照同步 fllower的lastZxid太老了,直接進行全量快照同步
  • DIFF 提案同步 不是很老,把fllower的lastZxid到leader的lastZxid之間的提案重新發給fllower進行同步
  • TRUNC 同步 超過了leader的lastZxid,發送指令讓fllower lastZxid 到 leader lastZxid 之間的提案進行刪除

fllower同步完成後發送ACK-LD給leader,leader纔會將該fllower加入可用fllower列表。

3.Broadcast Phase 廣播階段

leader將client發過來的請求生成一個事務proposal,然後發送給Follower,多數Follower應答之後,Leader再發送Commit給全部的Follower讓其進行提交。

三、Raft協議

角色

  • 領導者
  • 跟隨者
  • 候選人

每個節點持久化的數據

  • currentTerm 類似zab的currentEpoch
  • term 類似zab的epoch

名詞解釋

  • 複製狀態機 不展開 raft協議的前提就是將所有的節點看做複製狀態機模型
  • 日誌 由logEntry組成,包含term_number,command,任期號和指令。

選舉

當沒有收到leader心跳一段時間(隨機時間),節點切換身份爲候選人節點,開始發起選舉,向其他節點並行請求其他節點給自己投票,請求數據包括term,和日誌索引,同時把自己的選票投給自己,其他節點收到請求後,比對收到的請求數據中的term和日誌索引是否與本地日誌相比,哪一個更新,如果請求節點的更新,則返回響應將票投給該leader。

上一步如何比較更新了? 優先比較任期編號,其次比較日誌索引

若一段時間(隨機時間)後沒有收到大部分選票,則選舉失敗,反之成功。

若在這段選舉時間內收到其他leader發送的數據包,將比對數據包中的term,如果比自己大,則停止選舉,切換爲跟隨者身份,反之繼續選舉。

選舉的結果:一定包含了所有已提交的日誌, 從而避免那些沒有含有所有已提交日誌的結點成爲候選人。

約束

1.日誌約束

  • 領導者的日誌只能增添而不能刪除
  • 日誌數據的流向只能從領導人到其它結點,
  • 不允許對日誌項做刪除或變更位置(改變索引)操作
  • 任期+索引 能夠確定一個唯一的logEntry
  • 當領導人與跟隨者的日誌不相同時, 跟隨者會用領導人的日誌覆蓋自身的

2. 安全性約束(Safety)

不允許領導人直接提交當前任期之前的日誌, 而必須是先嚐試提交當前任期的日誌,即把當前任期的日誌先嚐試複製到其他大多數節點(這個過程不只是當前任期當前索引的日誌會被複制,前面任期前面索引的日誌都會複製到跟隨者,並可能產生覆蓋,反正一切以領導者日誌爲準), 等到了提交這一步,判斷當前任期日誌之前的日誌是否已經提交(節點會維護一個 commitIndex, 標誌當前最新的已提交的日誌項的索引),如果沒有提交,則進行提交。 爲什麼這麼做,假設可以提交,在直接提交當前任期之前的日誌(這裏稱爲preLog)之後,leader突然宕機,導致不含有preLog的節點,但最新日誌中的任期號比較大的節點當選領導者(因爲其他節點中的日誌都沒他新),他最新日誌的索引可能和preLog相同,當要求日誌同步的時候,則可能覆蓋preLog,這是嚴重的錯誤,將導致已提交的日誌被覆蓋,所以限制了在提交preLog的時候,要求滿足一個條件,即就算自己宕機,下一個領導者因爲含有當前任期的日誌所以會獲得多數派節點的承認當選領導者,間接也會擁有preLog,保證preLog能夠同步給其他節點。

簡而言之,一條非當期任期的logEntry就算已經拷貝到了大多數結點上也不會提交,除非在當前任期Term內也提交了一條日誌,上一條日誌纔會被順帶提交。

日誌數據同步

領導者維護一個nextIndex列表,表示每個節點需要接受的下一個日誌項的索引。在剛剛當選領導者的時候,所有節點的nextIndex爲領導者最大的index+1。領導者給跟隨者發送該節點nextIndex標識的日誌項的時候也會攜帶上一個日誌項的preTerm,preIndex,跟隨者比對是否含有preTertm,preIndex的日誌項,若沒有將拒絕此次日誌項同步,領導者則將nextIndex列表中,該節點的nextIndex-1,然後繼續發送日誌項,直到跟隨者不拒絕爲止。若此次日誌項本節點已經有了,則該日誌項將被覆蓋,以領導者發過來的日誌項爲準。當集羣中的大多數結點都獲得了某一日誌項副本之後, 領導人才會提交該日誌,才能進行下一日誌項的提交。

日誌壓縮

通過快照的方式壓縮日誌 快照中的日誌項必須是已提交過的, 集羣中的各個結點自主生成已提交的日誌項的快照, 領導人每隔一段時間也會將自己的快照廣播發送給集羣中的所有其它結點, 其它結點收到快照後會根據快照中說明的索引檢查自己是否已含有此快照中的全部信息, 如果沒有, 則刪除自己全部的日誌項, 然後應用這個快照, 若快照的最大索引小於自身的, 則結點簡單地將快照對應的索引之前的所有日誌項刪除, 並應用這個快照, 而自身原有的在此索引之後的日誌項仍然保留, 這樣以來, 即便是新加入集羣的結點, 也可以使用快照快速達到與領導人的同步。

四、三者對比

選舉觸發

  • raft 跟隨者沒有沒有收到leader心跳超時
  • zab 跟隨者 領導者 都可以發起選舉 領導者在沒有收到過半跟隨者心跳超時時觸發 跟隨者在心跳到不了領導者超時的時候觸發
  • Paxos 與具體實現有關 basic-Paxos中並沒有領導者

如何處理上一輪未提交的日誌(幽靈復現)

  • raft 先複製本輪日誌到大部分節點,再提交上一輪日誌
  • zab 採取激進的策略,對於所有過半還是未過半的日誌都判定爲提交,都將其應用到狀態機中
  • Paxos 沒有深入討論

腦裂問題

raft 不會,就算網絡分區產生腦裂,但也只有一個leader能提供服務,因爲需要過半支持,而在重新選舉的時候,服務不可用。 zab 不會,就算網絡分區產生腦裂,但也只有一個leader能提供服務,因爲需要過半支持,而在重新選舉的時候,服務不可用。 Paxos 允許 多主 所以可能出現

請求的連續性

  • raft 不可能先commit後面的日誌,在commit前面的日誌。
  • zab 也是連續的 通過鎖和隊列依次提交寫請求的命令
  • Paxos 不連續 連leader都沒有,每個節點都是平等的,如果要就某數據分歧達成一致都要走一次paxos

日誌同步

  • raft leader維護各個節點的nextIndex和前一條日誌preIndex,preTerm,各個節點比對是否有前一條相同任期,相同索引的日誌,若沒有則拒絕追加日誌,leader則更新nextIndex-1,然後接着發,直到不拒絕爲止。因爲日誌連續,所以能保證。
  • zab 在選舉爲準領導者的時候,直接進行recovery,以leader日誌爲準,不管提沒提交,直接進行同步
  • Paxos 沒有細講,同步一次就是一次paxos協議
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章