Ozone內部使用的RaftLeader/RaftFollower的一致性同步機理

前言


在之前的文章中,筆者提過Ozone內部使用的是基於Raft協議的一致性控制,以此保證Ozone Container操作請求在Pipeline節點上的一致性。但是這裏面具體是怎麼樣的一個過程呢?RaftLeader/RaftFollower的一致性同步這塊其實並不是實現在Ozone這個項目裏,而是在外部使用庫Apache Ratis裏的。本文筆者來聊聊Apache Ratis中RaftLeader、RaftFollower是如何做一致性的控制的。

Apache Ratis基於Raft協議的一致性同步過程


在之前的文章Apache Ratis的Ratis Server主從同步機制裏,筆者簡單闡述過其中的主要角色服務和原理過程,過程圖如下所示:
在這裏插入圖片描述
這裏再次引用下前文對於上述服務角色的介紹:

RetryCache,對於客戶端而言,Ratis Sever內部有RetryCache,爲了避免客戶端發起重複的請求操作。
Raft Log,Raft Log可以理解爲是Ratis Server的WAL,每次用戶的操作會被轉化爲transaction log然後被寫入到Raft Log中,如果log寫滿了,則會新創建Raft Log文件進行寫入。
LogAppender,此角色服務是將Leader內最新的transaction log發送到遠端的各個Follower服務中,並獲取返回結果。然後及時更新Raft Log的commit index。
StateMachineUpdater,此角色根據Raft Log當前的commit記錄,及時apply 最新committed的log entry到StateMachine中,然後purge掉commit index之前的log文件。同時它會定期給StateMachine做snapshot操作。StateMachineUpdater的功能有點類似於Checkpoint的角色功能。

不過上面提到的部分粒度比較粗,有很多細節部分沒有提到,比如RaftLeader/RaftFolloer如何認定本地的RaftLog是已經Commit的,又比如說RaftLog和StateMachine間是如何進行交互的等等。下面我們對這裏面的細節內容做更進一步的分析。

Apache Ratis內部RaftLeader/RaftFollower過程調用分析


在本小節的過程調用分析中,我們還是同樣會有上面提到的角色服務:

  • RaftLeader/RaftFollower
  • RaftLog
  • StateMachineUpdater
  • StateMachine

在整個RaftLeader/RaftFollower的同步過程中,總共可以拆分爲3個階段:

第一個階段,RaftLeader的本地寫Raft log操作。RaftLeader本地接受到客戶端的操作請求,然後觸發寫本地Raft log操作。在此過程中,StateMachine會進行請求transaction的驗證操作,驗證通過,允許RaftLeader執行寫log entry的操作。RaftLeader在寫log entry時,如果log entry附有額外數據,此部分數據將會被額外寫入StateMachine內。Write log entry如若達到Raft log flush閾值條件時,則會進行一次flush到外部持久存儲的操作,同時觸發StateMachine的flushStateMachineData的操作。OK到此爲止,此過程中新寫入的log還沒有被Committed。

第二個階段,RaftLeader發送append log的請求到RaftFollower上。在此過程中,將會進行如下步驟:

RaftLeader構造append log的請求實例,此過程將會從本地log中讀取log entry數據,如果此log entry數據還帶有StateMachine data的時候,還需要從StateMachine中讀取相應的數據。

RaftLeader發送append log的請求到各個Follower上,Follower接受到請求後,首先更新自身log的Commit Index爲Leader的Commit Index。然後通知本地StateMachineUpdater去apply到最新Commit Index的Raft log。Follower倘若發現接受到的新Raft log和本地不一致時(在重新選舉產生新Leader時,會有可能導致這種請求發生),則進行本地log的truncate操作。如果一致的話,則進行後續本地log entry的寫操作,此過程和第一階段RaftLeader寫本地log的過程類似,也會有StateMachine的相關觸發操作。

這個過程還沒有結束,Follower在執行完本地的log append的操作後,會返回RaftLeader回覆結果,附有Follow本地最新的log信息,包括已經寫出的Index和下一個Index。RaftLeader收到後,判斷是否半數以上已經成功接受到新append的log entry,則進行Commit Index的更新,更新到上次append成功到Follower的那個Index位置上。

第三個階段,RaftLeader通知本地的StateMachineUpdater去apply最新的Raft log到StateMachine中。這個過程RaftLeader和Follower的邏輯是一致的。

在上述過程裏,我們可以看到,RaftLeader是判斷RaftLog是否可以標記爲Commit狀態的確定者,確定的標準爲它本地新寫的Raft log是否已經被半數以上的Follower接受到並寫出到了它們的Raft log內,則進行Leader本地的Commit Index更新。而Follower的Commit則取決於Leader發來的最新的Commit Index。換句話說,Follower只要等RaftLeader告訴我可以更新哪個最新的Commit Index了,然後我就apply最新的log entry到StateMachine中去

上述的交互過程如下流程圖所示(同一個顏色過程表示屬於同一階段過程):
在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章