
- SOFAJRaft 概述 -
咱們對Raft協定已經進行了原理的解析,接下去咱們從通過SOFAJRaft 架構的核心流程剖析加深對Raft協定的了解。SOFAJRaft 是一個純 Java 的 Raft 算法實作庫, 基于百度 braft 實作而來, 使用 Java 重寫了所有功能, 支援:
上司人選舉和基于優先級的半确定性上司人選舉。
日志複制和恢複。
快照和日志壓縮。
隻讀成員(learner)。
叢集成員管理,添加節點,删除節點,替換節點等。
完全并發複制。
容錯能力。
非對稱網絡分區容忍性。
當法定人數同伴都死亡的解決方法。
管道複制
線性一緻讀,ReadIndex/LeaseRead。
額外擴充了一些功能:
對稱網絡分區容忍性
重新開機後的轉移領袖、負載均衡場景實作
更豐富的名額統計展示
通過Jepsen一緻性驗證測試
包含嵌入式分布式KV存儲實作
整體項目如下:

- 領袖選舉 -
SOFAJRaft 的選舉主要通過判單兩個屬性:LogIndex 和 Term;Term 即任期,LogIndex即送出到 raft group 中的任務都将序列化為一條日志存儲下來,每條日志一個編号,在整個 raft group 内單調遞增并複制到每個 raft 節點。可以了解為事務id。投票處理的邏輯主要在 com.alipay.sofa.jraft.core.NodeImpl中,主要有四個函數:
處理處理預投票請求
Message handlePreVoteRequest(request)
預投票
void preVote()
處理投票請求
Message handleRequestVoteRequest(request)
投票
electSelf()
整體流程如下:
Candidate(候選人) 被 Election timeout觸發
Candidate 開始嘗試發起 pre-vote 預投票
Follower(追随者) 判斷是否認可該 pre-vote request
Candidate 根據 pre-vote response 來決定是否發起 RequestVoteRequest
Follower 判斷是否認可該 RequestVoteRequest
Candidate 根據 response 來判斷自己是否當選
使用預投票可以防止網絡抖動等特殊原因引起的瞬時失聯節點無故搗亂:候選者在發起投票之前,先發起預投票,如果沒有得到半數以上節點的回報,則候選者就會識趣的放棄參選,也就不會擡升全局的 Term。
投票源碼:
預投票源碼:

- 存儲機制 -
SOFAJRaft 存儲子產品分為:
Log 存儲記錄 Raft 配置變更和使用者送出任務日志,把日志從 Leader 複制到其他節點上面;
LogStorage 是日志存儲實作,預設實作基于 RocksDB 存儲,通過 LogStorage 接口擴充自定義日志存儲實作;核心接口包括:
傳回日志裡的首/末個日志索引;
按照日志索引擷取 Log Entry 及其任期;
把單個/批量 Log Entry 添加到日志存儲;
從 Log 存儲頭部/末尾删除日志;
删除所有現有日志,重置下任日志索引。
LogManager 負責調用底層日志存儲 LogStorage,針對日志存儲調用進行緩存、批量送出、必要的檢查和優化。
checkAndResolveConflict(entries, done)
檢查Node節點,解決日志沖突。
配置管理器:緩存配置變更
LogsInMemory緩存日志Entries
offerEvent(done, type)
Disruptor隊列釋出other類型事件
appendToStorage(toAppend)
回調事件處理器StableClosureEventHandler存儲日志
Meta 存儲即元資訊存儲記錄 Raft 實作的内部狀态,比如目前 term,、投票給哪個節點等資訊
RaftMetaStorage 元資訊存儲實作,定義 Raft 中繼資料的 Metadata 存儲子產品核心 API 接口包括:
設定/擷取 Raft 中繼資料的目前任期 Term;
配置設定/查詢 Raft 元資訊的 PeerId 節點投票。
Snapshot 存儲用于存放使用者的狀态機 Snapshot 及元資訊,用于Node重新開機重建整個狀态機執行個體。
SnapshotStorage 用于 snapshot 存儲實作,定義 Raft 狀态機的 Snapshot 存儲子產品核心接口包括:
設定 filterBeforeCopyRemote ,為 true 表示複制到遠端之前過濾資料;
建立快照編寫器;
打開快照閱讀器;
從遠端 Uri 複制資料;
啟動從遠端 Uri 複制資料的複制任務;
配置 SnapshotThrottle,SnapshotThrottle 用于重盤讀/寫場景限流的,比如磁盤讀寫、網絡帶寬。
SnapshotExecutor 用于 snapshot 實際存儲、遠端安裝、複制的管理。
狀态機快照 doSnapshot(done)
安裝快照 installSnapshot(request, response, done)。
LogManager 調用日志存儲 LogStorage 實作邏輯:
SnapshotExecutor 狀态機快照和遠端安裝鏡像實作邏輯:

- 一緻性狀态機 -
通過存儲的設計,在引入狀态機機制,就可以完成一緻性狀态機。SOFAJRaft狀态機組成有:
StateMachine:業務邏輯實作的主要接口,狀态機運作在每個 raft 節點上,送出的 task 如果成功,最終都會複制應用到每個節點的狀态機上。,核心是 onApply(Iterator) 方法,應用通過 Node#apply(task) 送出的日志到業務狀态機。
FSMCaller:封裝對業務 StateMachine 的狀态轉換的調用以及日志的寫入等,一個有限狀态機的實作,做必要的檢查、請求合并送出和并發處理等。
SOFAJRaft Node節點利用日志複制完成資料同步,主要組成有:
Replicator:用于 leader 向 follower 複制日志,也就是 raft 中的 appendEntries 調用,包括心跳存活檢查等。
ReplicatorGroup: 用于單個 RAFT Group 管理所有的 replicator,必要的權限檢查和派發。

- 總結 -
本文通過簡單介紹了下SOFAJRaft的選舉實作、存儲機制、狀态機和日志複制四個方面。基本上完成了Raft實作的核心實作。但SOFAJRaft還有更多核心及優化,因為篇幅原因沒有進入細細剖析。如果咱們自實作Raft協定,基本上也是實作這幾個主流程即可完成簡版Raft了。關于Raft協定暫時先告一段路,接下去準備開寫ZAB協定。

- 作者介紹 -
林淮川
畢業于西安交通大學;奈學教育《百萬架構師訓練營》講師、企業級源碼内源負責人,前大樹金融進階架構師、技術委員會開創者、技術總監;前天陽宏業交易事業部技術主管;多年網際網路金融行業(ToB)經驗。
本文分享自微信公衆号 - 川聊架構(gh_44ec4115d261)。
如有侵權,請删除。