中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

SOFAJRaft-RheaKV MULTI-RAFT-GROUP實現分析SOFAJRaft的實現原理

發布時間:2021-07-05 16:32:13 來源:億速云 閱讀:190 作者:chen 欄目:大數據

這篇文章主要介紹“SOFAJRaft-RheaKV MULTI-RAFT-GROUP實現分析SOFAJRaft的實現原理”,在日常操作中,相信很多人在SOFAJRaft-RheaKV MULTI-RAFT-GROUP實現分析SOFAJRaft的實現原理問題上存在疑惑,小編查閱了各式資料,整理出簡單好用的操作方法,希望對大家解答”SOFAJRaft-RheaKV MULTI-RAFT-GROUP實現分析SOFAJRaft的實現原理”的疑惑有所幫助!接下來,請跟著小編一起來學習吧!

SOFAStack Scalable Open Financial  Architecture Stack 是螞蟻金服自主研發的金融級分布式架構,包含了構建金融級云原生架構所需的各個組件,是在金融場景里錘煉出來的最佳實踐。

前言

RheaKV 是首個以 JRaft 為基礎實現的一個原生支持分布式的嵌入式鍵值(key、value)數據庫,現在本文將從 RheaKV 是如何利用 MULTI-RAFT-GROUP 的方式實現 RheaKV 的高性能及容量的可擴展性的,從而進行全面的源碼、實例剖析。

MULTI-RAFT-GROUP

通過對 Raft 協議的描述我們知道:用戶在對一組 Raft 系統進行更新操作時必須先經過 Leader,再由 Leader 同步給大多數 Follower。而在實際運用中,一組 Raft 的 Leader 往往存在單點的流量瓶頸,流量高便無法承載,同時每個節點都是全量數據,所以會受到節點的存儲限制而導致容量瓶頸,無法擴展。

MULTI-RAFT-GROUP 正是通過把整個數據從橫向做切分,分為多個 Region 來解決磁盤瓶頸,然后每個 Region 都對應有獨立的 Leader 和一個或多個 Follower 的 Raft 組進行橫向擴展,此時系統便有多個寫入的節點,從而分擔寫入壓力,圖如下:

SOFAJRaft-RheaKV MULTI-RAFT-GROUP實現分析SOFAJRaft的實現原理cdn.nlark.com/yuque/0/2019/jpeg/325890/1557569369003-7d4762a0-2590-48bc-afc9-b4e53b520054.jpeg">

此時磁盤及 I/O 瓶頸解決了,那多個 Raft Group 是如何協作的呢,我們接著往下看。

選舉及復制

RheaKV 主要由 3 個角色組成:PlacementDriver(以下成為 PD) 、Store、Region。由于 RheaKV 支持多組 Raft,所以比單組場景多出一個 PD 角色,用來調度以及收集每個 Store 及 Region 的基礎信息。

SOFAJRaft-RheaKV MULTI-RAFT-GROUP實現分析SOFAJRaft的實現原理

PlacementDriver

PD 負責整個集群的管理調度、Region ID 生成等。此組件非必須的,如果不使用 PD,設置 PlacementDriverOptions 的 fake 屬性為 true 即可。PD 一般通過 Region 的心跳返回信息進行對 Region 調度,Region 處理完后,PD 則會在下一個心跳返回中收到 Region 的變更信息來更新路由及狀態表。

Store

通常一個 Node 負責一個 Store,Store 可以被看作是 Region 的容器,里面存儲著多個分片數據。Store 會向 PD 主動上報 StoreHeartbeatRequest 心跳,心跳交由 PD 的 handleStoreHeartbeat 處理,里面包含該 Store 的基本信息,比如,包含多少 Region,有哪些 Region 的 Leader  在該 Store 等。

Region

Region 是數據存儲、搬遷的最小單元,對應的是 Store 里某個實際的數據區間。每個 Region 會有多個副本,每個副本存儲在不同的 Store,一起組成一個Raft Group。Region 中的 Leader 會向 PD 主動上報 RegionHeartbeatRequest 心跳,交由 PD 的 handleRegionHeartbeat 處理,而 PD 是通過 Region 的 Epoch 感知 Region 是否有變化。

RegionRouteTable 路由表組件

Muti-Raft-Group 的多 Region 是通過 RegionRouteTable 路由表組件進行管理的,可通過 addOrUpdateRegion、removeRegion 進行添加、更新、移除 Region,也包括 Region 的拆分。目前暫時還未實現 Region 的聚合,后面會考慮實現。

分區邏輯與算法 Shard

SOFAJRaft-RheaKV MULTI-RAFT-GROUP實現分析SOFAJRaft的實現原理

“讓每組 Raft 負責一部分數據。”

數據分區或者分片算法通常就是 Range 和 Hash,RheaKV 是通過 Range 進行數據分片的,分成一個個 Raft Group,也稱為 Region。這里為何要設計成 Range 呢?原因是 Range 切分是按照對 Key 進行字節排序后再做每段每段切分,像類似 scan 等操作對相近 key 的查詢會盡可能集中在某個 Region,這個是 Hash 無法支持的,就算遇到單個 Region 的拆分也會更好處理一些,只用修改部分元數據,不會涉及到大范圍的數據挪動。

當然 Range 也會有一個問題那就是,可能會存在某個 Region 被頻繁操作成為熱點 Region。不過也有一些優化方案,比如 PD 調度熱點 Region 到更空閑的機器上,或者提供 Follower 分擔讀的壓力等。

Region 和 RegionEpoch 結構如下:

class Region {
		long              id;            // region id
    // Region key range [startKey, endKey)
		byte[]            startKey;      // inclusive
		byte[]            endKey;        // exclusive
		RegionEpoch       regionEpoch;   // region term
		List<Peer>        peers;         // all peers in the region
}
class RegionEpoch {
		// Conf change version, auto increment when add or remove peer
  	long              confVer;
  	// Region version, auto increment when split or merge
  	long              version;
}
class Peer {
		long              id;
    long              storeId;
    Endpoint          endpoint;
}

Region.id:為 Region 的唯一標識,通過 PD 全局唯一分配。

Region.startKey、Region.endKey:這個表示的是 Region 的 key 的區間范圍 [startKey, endKey),特別值得注意的是針對最開始 Region 的 startKey,和最后 Region 的 endKey 都為空。

Region.regionEpoch:當 Region 添加和刪除 Peer,或者 split 等,此時 regionEpoch 就會發生變化,其中 confVer 會在配置修改后遞增,version 則是每次有 split 、merge(還未實現)等操作時遞增。

Region.peers:peers 則指的是當前 Region 所包含的節點信息,Peer.id 也是由 PD 全局分配的,Peer.storeId 代表的是 Peer 當前所處的 Store。

讀與寫 Read / Write

由于數據被拆分到不同 Region 上,所以在進行多 key 的讀、寫、更新操作時需要操作多個 Region,這時操作前我們需要得到具體的 Region,然后再單獨對不同 Region 進行操作。我們以在多 Region上 scan 操作為例, 目標是返回某個 key 區間的所有數據: 

  1. 我們首先看 scan 方法的核心調用方法 internalScan 的異步實現:

例如:com.alipay.sofa.jraft.rhea.client.DefaultRheaKVStore#scan(byte[], byte[], boolean, boolean)

SOFAJRaft-RheaKV MULTI-RAFT-GROUP實現分析SOFAJRaft的實現原理

我們很容易看到,在調用 scan 首先讓 PD Client 通過 RegionRouteTable.findRegionsByKeyRange 檢索 startKey、endKey 所覆蓋的 Region,最后返回的可能為多個 Region,具體 Region 覆蓋檢索方法如下:

SOFAJRaft-RheaKV MULTI-RAFT-GROUP實現分析SOFAJRaft的實現原理

檢索相關變量定義如下:

SOFAJRaft-RheaKV MULTI-RAFT-GROUP實現分析SOFAJRaft的實現原理

我們可以看到整個 RheaKV 的 range 路由表是通過 TreeMap 的進行存儲的,正呼應我們前面講過所有的 key 是通過對應字節進行排序存儲。對應的 Value 為該 Region 的 RegionId,隨后我們通過 Region 路由 regionTable 查出即可。

現在我們得到 scan 覆蓋到的所有 Region:List<Region> 在循環查詢中我們看到有一個“retryCause -> {}”的 Lambda 表達式很容易看出這里是加持異常重試處理,后面我們會講到,接下來會通過 internalRegionScan 查詢每個 Region 的結果。具體源碼如下:

SOFAJRaft-RheaKV MULTI-RAFT-GROUP實現分析SOFAJRaft的實現原理

這里也同樣有一個重試處理,可以看到代碼中根據當前是否為 Region 節點來決定是本機查詢還是通過RPC進行查詢,如果是本機則調用 rawKVStore.scan() 進行本地直接查詢,反之通過 rheaKVRpcService 進行 RPC 遠程節點查詢。最后每個 Region 查詢都返回為一個 future,通過 FutureHelper.joinList 工具類 CompletableFuture.allOf 異步并發返回結果 List<KVEntry>

  1. 我們再看看寫入具體流程。相比 scan 讀,put 寫相對比較簡單,只需要針對 key 計算出對應 Region 再進行存儲即可,我們可以看一個異步 put 的例子。

例如:com.alipay.sofa.jraft.rhea.client.DefaultRheaKVStore#put(java.lang.String, byte[])

SOFAJRaft-RheaKV MULTI-RAFT-GROUP實現分析SOFAJRaft的實現原理

我們可以發現 put 基礎方法是支持 batch 的,即可成批提交。如未使用 batch 即直接提交,具體邏輯如下:

SOFAJRaft-RheaKV MULTI-RAFT-GROUP實現分析SOFAJRaft的實現原理

通過 pdClinet 查詢對應存儲的 Region,并且通過 regionId 拿到 RegionEngine,再通過對應存儲引擎 KVStore 進行 put,整個過程同樣支持重試機制。我們再回過去看看 batch 的實現,很容易發現利用到了 Disruptor 的 RingBuffer 環形緩沖區,無鎖隊列為性能提供了保障,代碼現場如下:

SOFAJRaft-RheaKV MULTI-RAFT-GROUP實現分析SOFAJRaft的實現原理

Split / Merge

  1. 什么時候 Region 會拆分?

前面我們有講過,PD 會在 Region 的 heartBeat 里面對 Region 進行調度,當某個 Region 里的 keys 數量超過預設閥值,我們即可對該 Region 進行拆分,Store 的狀態機 KVStoreStateMachine 即收到拆分消息進行拆分處理。具體拆分源碼如下:

KVStoreStateMachine.doSplit 源碼如下:

SOFAJRaft-RheaKV MULTI-RAFT-GROUP實現分析SOFAJRaft的實現原理

StoreEngine.doSplit 源碼如下:

SOFAJRaft-RheaKV MULTI-RAFT-GROUP實現分析SOFAJRaft的實現原理

我們可以輕易的看到從原始 parentRegion 切分成 region 和 pRegion,并重設了 startKey、endKey 和版本號,并添加到 RegionEngineTable 注冊到 RegionKVService,同時調用 pdClient.getRegionRouteTable().splitRegion() 方法進行更新存儲在 PD 的 Region 路由表。

  1. 什么時候需要對 Region 進行合并?

既然數據過多需要進行拆分,那 Region 進行合并那就肯定是 2 個或者多個連續的 Region 數據量明顯小于絕大多數 Region 容量則我們可以對其進行合并。這一塊后面會考慮實現。

RegionKVService 結構及實現分析

StoreEngine

通過上面我們知道,一個 Store 即為一個節點,里面包含著一個或者多個 RegionEngine,一個 StoreEngine 通常通過 PlacementDriverClient 對 PD 進行調用,同時擁有 StoreEngineOptions 配置項,里面配置著存儲引擎和節點相關配置。

  1. 我們以默認的 DefaultRheaKVStore 加載 StoreEngine 為例,DefaultRheaKVStore 實現了 RheaKVStore 接口的基礎功能,從最開始 init 方法,根據 RheaKVStoreOptions 加載了 pdClinet 實例,隨后加載 storeEngine。

  2. 在 StoreEngine 啟動的時候,首先會去加載對應的 StoreEngineOptions 配置,構建對應的 Store 配置,并且生成一致性讀的線程池 readIndexExecutor、快照線程池 snapshotExecutor、RPC 的線程池 cliRpcExecutor、Raft 的 RPC 線程池 raftRpcExecutor,以及存儲 RPC 線程池 kvRpcExecutor、心跳發送器 HeartbeatSender 等,如果打開代碼,我們還能看到 metricsReportPeriod,打開配置可以進行性能指標監控。

  3. 在 DefaultRheaKVStore 加載完所有工序之后,便可使用 get、set、scan 等操作,還包含對應同步、異步操作。

在這個過程中里面的 StoreEngine 會記錄著 regionKVServiceTable、regionEngineTable,它們分別掌握著具體每個不同的 Region 存儲的操作功能,對應的 key 即為 RegionId。

RegionEngine

每個在 Store 里的 Region 副本中,RegionEngine 則是一個執行單元。它里面記錄著關聯著的 StoreEngine 信息以及對應的 Region 信息。由于它也是一個選舉節點,所以也包含著對應狀態機 KVStoreStateMachine,以及對應的 RaftGroupService,并啟動里面的 RpcServer 進行選舉同步。

這個里面有個transferLeadershipTo方法,這個可被調用用于平衡當前節點分區的Leader,避免壓力重疊。

DefaultRegionKVService 是 RegionKVService 的默認實現類,主要處理對 Region 的具體操作。

RheaKV FailoverClosure 解讀

需要特別講到的是,在具體的 RheaKV 操作時,FailoverClosure 擔任著比較重要的角色,也給整個系統增加了一定的容錯性。假如在一次 scan 操作中,如果跨 Store 需要多節點 scan 數據的時候,任何網絡抖動都會造成數據不完整或者失敗情況,所以允許一定次數的重試有利于提高系統的可用性,但是重試次數不宜過高,如果出現網絡堵塞,多次 timeout 級別失敗會給系統帶來額外的壓力。這里只需要在 DefaultRheaKVStore 中,進行配置 failoverRetries 設置次數即可。

RheaKV PD 之 PlacementDriverClient 

PlacementDriverClient 接口主要由 AbstractPlacementDriverClient 實現,然后 FakePlacementDriverClient、RemotePlacementDriverClient 為主要功能。FakePlacementDriverClient 是當系統不需要 PD 的時候進行 PD 對象的模擬,這里主要講到 RemotePlacementDriverClient。

  1. RemotePlacementDriverClient 通過PlacementDriverOptions 進行加載,并根據基礎配置刷新路由表;

  2. RemotePlacementDriverClient 承擔著對路由表RegionRouteTable 的管控,例如獲取Store、路由、Leader節點信息等;

  3. RemotePlacementDriverClient 還包含著 CliService,通過 CliService 外部可對復制節點進行操作運維,如addReplica、removeReplica、transferLeader。

總結

由于很多傳統存儲中間件并不原生支持分布式,所以一直少有體感,Raft 協議是一套比較比較好理解的共識協議,SOFAJRaft 通俗易懂是一個非常好的代碼和工程范例,同時 RheaKV 也是一套非常輕量化支持多存儲結構可分片的嵌入式數據庫。寫一篇代碼分析文章也是一個學習和進步的過程,由此我們也可以窺探到了一些數據庫的基礎實現,祝愿社區能在 SOFAJRaft / RheaKV 基礎上構建更加靈活和自治理的系統和應用。

到此,關于“SOFAJRaft-RheaKV MULTI-RAFT-GROUP實現分析SOFAJRaft的實現原理”的學習就結束了,希望能夠解決大家的疑惑。理論與實踐的搭配能更好的幫助大家學習,快去試試吧!若想繼續學習更多相關知識,請繼續關注億速云網站,小編會繼續努力為大家帶來更多實用的文章!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

武胜县| 青冈县| 白山市| 榆林市| 封丘县| 大安市| 岳阳市| 图片| 巴林左旗| 青田县| 奇台县| 财经| 贡山| 合川市| 莱州市| 鄯善县| 兴安盟| 苏尼特右旗| 屏南县| 九江市| 甘肃省| 沙坪坝区| 科技| 仁寿县| 新河县| 辉县市| 田林县| 通道| 邹城市| 昔阳县| 高要市| 凉城县| 象山县| 开封市| 萍乡市| 德化县| 夏邑县| 阳朔县| 呈贡县| 阳山县| 邵阳县|