SOFAStacknode
Scalable Open Financial Architecture Stackgit
是螞蟻金服自主研發的金融級分佈式架構,包含了構建金融級雲原生架構所需的各個組件,是在金融場景裏錘鍊出來的最佳實踐。github
本文爲《剖析 | SOFAJRaft 實現原理》第二篇,本篇做者米麒麟,來自陸金所。《剖析 | SOFAJRaft 實現原理》系列由 SOFA 團隊和源碼愛好者們出品,項目代號:<SOFA:JRaftLab/>,目前領取已經完成,感謝你們的參與。算法
SOFAJRaft 是一個基於 Raft 一致性算法的生產級高性能 Java 實現,支持 MULTI-RAFT-GROUP,適用於高負載低延遲的場景。數據庫
SOFAJRaft :github.com/sofastack/s…緩存
SOFAJRaft-RheaKV 是基於 SOFAJRaft 和 RocksDB 實現的嵌入式、分佈式、高可用、強一致的 KV 存儲類庫,SOFAJRaft 是基於 Raft 一致性算法的生產級高性能 Java 實現,支持 Multi-Raft-Group。SOFAJRaft-RheaKV 集羣主要包括三個核心組件:PD,Store 和 Region。本文將圍繞 SOFAJRaft-RheaKV 架構設計,存儲概覽,核心模塊,使用場景以及基於 Raft 實現等方面剖析 SOFAJRaft-RheaKV 基於 SOFAJRaft 實現原理,闡述如何使用 Raft 協議支持 KV 存儲類庫功能特性:安全
SOFAJRaft-RheaKV 是一個輕量級的分佈式的嵌入式的 KV 存儲 Library, RheaKV 包含在 SOFAJRaft 項目裏,是 SOFAJRaft 的子模塊。SOFAJRaft-RheaKV 定位是嵌入式 jar 包方式嵌入到應用中,涵蓋如下功能特性:bash
SOFAJRaft-RheaKV 存儲類庫主要包括 PD,Store 和 Region 三個核心組件,支持輕量級的狀態/元信息存儲以及集羣同步,分佈式鎖服務使用場景:數據結構
SOFAJRaft-RheaKV 存儲層爲可插拔設計,實現 RawKVStore 存儲接口,目前 StoreEngine 存儲引擎支持 MemoryDB 和 RocksDB 兩種實現:架構
SOFAJRaft-RheaKV 存儲引擎基於 MemoryDB 和 RocksDB 實現 KV 存儲入口:
com.alipay.sofa.jraft.rhea.storage.RawKVStore
com.alipay.sofa.jraft.rhea.storage.MemoryRawKVStore
com.alipay.sofa.jraft.rhea.storage.RocksRawKVStore複製代碼
SOFAJRaft-RheaKV 數據強一致性依靠 SOFAJRaft 同步數據到其餘副本 Replication, 每一個數據變動都會落地爲一條 Raft 日誌, 經過 Raft 協議日誌複製功能將數據安全可靠地同步到同 Raft Group 的所有節點裏。
SOFAJRaft-RheaKV 核心模塊包括 KV 模塊[RheaKVStore 基於 RegionRouteTable 路由表使用 RaftRawKVStore 存儲 KeyValue],PD 模塊[PlacementDriverServer 基於 StoreHeartbeat/RegionHeartbeat 心跳平衡節點分區 Leader 以及分裂]。
PD 模塊主要參考 TIKV 的設計理念,目前只實現自動平衡全部節點的分區 Leader 以及自動分裂。
RheaKV 是基於 SOFAJRaft 實現的嵌入式、分佈式、高可用、強一致的 KV 存儲類庫,TiKV 是一個分佈式的 KV 系統,採用 Raft 協議保證數據的強一致性,同時使用 MVCC + 2PC 方式實現分佈式事務的支持,二者如何基於 Raft協議實現 KV 存儲?
RaftRawKVStore 是 RheaKV 基於 Raft 複製狀態機 KVStoreStateMachine 的 RawKVStore 接口 KV 存儲實現,調用 applyOperation(kvOperation,kvStoreClosure) 方法根據讀寫請求申請指定 KVOperation 操做,申請鍵值操做處理邏輯:
RheaKV 基於狀態機 KVStoreStateMachine 的 RaftRawKVStore 存儲 Raft 實現入口:
com.alipay.sofa.jraft.rhea.storage.RaftRawKVStore複製代碼
RheaKV 運行在每一個 Raft 節點上面的狀態機 KVStoreStateMachine 實現入口:
com.alipay.sofa.jraft.rhea.storage.KVStoreStateMachine 複製代碼
RheaKV 是一個要保證線性一致性的分佈式 KV 存儲引擎,所謂線性一致性,一個簡單的例子是在 T1 的時間寫入一個值,那麼在 T1 以後讀必定能讀到這個值,不可能讀到 T1 以前的值。由於 Raft 協議是爲了實現分佈式環境下面線性一致性的算法,因此經過 Raft 很是方便的實現線性 Read,即將任何的讀請求走一次 Raft Log,等 Log 日誌提交以後在 apply 的時候從狀態機裏面讀取值,必定可以保證此讀取到的值是知足線性要求的。由於每次 Read 都須要走 Raft 流程,因此性能是很是的低效的,SOFAJRaft 實現 Raft 論文提到 ReadIndex 和 Lease Read 優化,提供基於 Raft 協議的 ReadIndex 算法的更高效率的線性一致讀實現,ReadIndex 省去磁盤的開銷,結合 SOFAJRaft 的 Batch + Pipeline Ack + 全異步機制大幅度提高吞吐。RaftRawKVStore 接收 get/multiGet/scan/getSequence 讀請求都使用 Node
#
readIndex
(
requestContext
,
readIndexClosure
)
發起一次線性一致讀請求,當可以安全讀取的時候傳入的 ReadIndexClosure 將被調用,正常狀況從狀態機中讀取數據返回給客戶端,readIndex 讀取失敗嘗試應用鍵值讀操做申請任務於 Leader 節點的狀態機 KVStoreStateMachine,SOFAJRaft 保證讀取的線性一致性。線性一致讀在任何集羣內的節點發起,並不須要強制要求放到 Leader 節點上面,將請求散列到集羣內的全部節點上,下降 Leader 節點的讀取壓力。RaftRawKVStore 的 get 讀操做發起一次線性一致讀請求的調用:
// KV 存儲實現線性一致讀
public void get(final byte[] key, final boolean readOnlySafe, final KVStoreClosure closure) {
if (!readOnlySafe) {
this.kvStore.get(key, false, closure);
return;
}
// 調用 readIndex 方法,等待回調執行
this.node.readIndex(BytesUtil.EMPTY_BYTES, new ReadIndexClosure() {
@Override
public void run(final Status status, final long index, final byte[] reqCtx) {
if (status.isOk()) {
// ReadIndexClosure 回調成功,從 RawKVStore 調用 get 方法讀取最新數據返回
RaftRawKVStore.this.kvStore.get(key, true, closure);
return;
}
// 特殊狀況譬如發生選舉讀請求失敗,嘗試申請 Leader 節點的狀態機
RaftRawKVStore.this.readIndexExecutor.execute(() -> {
if (isLeader()) {
LOG.warn("Fail to [get] with 'ReadIndex': {}, try to applying to the state machine.", status);
// If 'read index' read fails, try to applying to the state machine at the leader node
applyOperation(KVOperation.createGet(key), closure);
} else {
LOG.warn("Fail to [get] with 'ReadIndex': {}.", status);
// Client will retry to leader node
new KVClosureAdapter(closure, null).run(status);
}
});
}
});
}複製代碼
TiDB 是 PingCAP 公司設計的開源分佈式 HTAP (Hybrid Transactional and Analytical Processing) 數據庫,TiDB 集羣主要包括三個核心組件:TiDB Server,PD Server 和 TiKV Server。TiKV Server 負責存儲數據,從外部看 TiKV 是一個分佈式的提供事務的 Key-Value 存儲引擎。存儲數據的基本單位是 Region,每一個 Region 負責存儲一個 Key Range(從 StartKey 到 EndKey 的左閉右開區間)的數據,每一個 TiKV 節點負責多個 Region。TiKV 使用 Raft 協議作複製,保持數據的一致性和容災。副本以 Region 爲單位進行管理,不一樣節點上的多個 Region 構成一個 Raft Group,互爲副本。數據在多個 TiKV 之間的負載均衡由 PD 調度,這裏也是以 Region 爲單位進行調度。TiKV 利用 Raft 來作數據複製,每一個數據變動都會落地爲一條 Raft 日誌,經過 Raft 的日誌複製功能,將數據安全可靠地同步到 Group 的多數節點。TiKV 總體架構包括 Placement Driver,Node,Store 以及 Region 組件:
TiKV 使用 Raft 一致性算法來保證數據的安全,默認提供的是三個副本支持,這三個副本造成了一個 Raft Group。當 Client 須要寫入 TiKV 數據的時候,Client 將操做發送給 Raft Leader,在 TiKV 裏面稱作 Propose,Leader 將操做編碼成一個 Entry,寫入到本身的 Raft Log 裏面,稱作 Append。Leader 也會經過 Raft 算法將 Entry 複製到其餘的 Follower 上面,叫作 Replicate。Follower 收到這個 Entry 以後也會一樣進行 Append 操做,順帶告訴 Leader Append 成功。當 Leader 發現此 Entry 已經被大多數節點 Append,認爲此 Entry 已是 Committed 的,而後將 Entry 裏面的操做解碼出來,執行而且應用到狀態機裏面,叫作 Apply。TiKV 提供 Lease Read,對於 Read 請求直接發給 Leader,若是 Leader 肯定自身的 Lease 沒有過時,那麼直接提供 Read 服務不用執行一次 Raft 流程。若是 Leader 發現 Lease 已通過期,就會強制執行一次 Raft 流程進行續租而後再提供 Read 服務。TiKV 是以 Region 爲單位作數據的複製,也就是一個 Region 的數據保存多個副本,將每個副本叫作一個 Replica。Replica 之間是經過 Raft 來保持數據的一致,一個 Region 的多個 Replica 保存在不一樣的節點上構成一個 Raft Group,其中一個 Replica 做爲此 Group 的 Leader,其餘的 Replica 做爲 Follower。全部的讀和寫都是經過 Leader 進行,再由 Leader 複製給 Follower。
本文圍繞 SOFAJRaft-RheaKV 架構存儲,模塊流程以及基於 Raft 實現細節方面闡述 SOFAJRaft-RheaKV 基本原理,剖析 SOFAJRaft-RheaKV 如何使用 JRaft 一致性協議日誌複製功能保證數據的安全和容災,參考 TiKV 基於 Raft 算法實現了分佈式環境數據的強一致性。
SOFA Meetup #2 上海站《使用 SOFAStack 快速構建微服務》期待你的參與❤~
5 月 26 日,本週日,SOFAStack 開源核心成員集體出動。本期咱們將側重於各個落地的實際場景進行架構解析。
分佈式事務 Seata 詳解、與 Spring Cloud 生態的融合案例、使用 SOFAStack 快速構建微服務 Demo 實操、更有最新開源的《讓 AI 像 SQL 同樣簡單 — SQLFlow Demo 》首秀,週日不見不散~
戳連接便可報名:tech.antfin.com/community/a…
公衆號:金融級分佈式架構(Antfin_SOFA)