源碼分析 RocketMQ DLedger 多副本存儲實現

@(本節目錄)
RocketMQ DLedger 的存儲實現思路與 RocketMQ 的存儲實現思路相似,本文就不再從源碼角度詳細剖析其實現,只是點出其實現關鍵點。我們不妨簡單回顧一下 CommitLog 文件、ConsumeQueue 文件設計思想。

其文件組成形式如下:
在這裏插入圖片描述
正如上圖所示,多個 commitlog 文件組成一個邏輯上的連續文件,使用 MappedFileQueue 表示,單個 commitlog 文件使用 MappedFile 表示。

溫馨提示:如果想詳細瞭解 RocketMQ 關於存儲部分的講解,可以關注筆者的《RocketMQ 技術內幕》一書。

1、DLedger 存儲相關類圖

在這裏插入圖片描述

1.1 DLedgerStore

存儲抽象類,定義如下核心方法:

  • public abstract DLedgerEntry appendAsLeader(DLedgerEntry entry)
    向主節點追加日誌(數據)。
  • public abstract DLedgerEntry appendAsFollower(DLedgerEntry entry, long leaderTerm, String leaderId)
    向從節點同步日誌。
  • public abstract DLedgerEntry get(Long index)
    根據日誌下標查找日誌。
  • public abstract long getCommittedIndex()
    獲取已提交的下標。
  • public abstract long getLedgerEndTerm()
    獲取 Leader 當前最大的投票輪次。
  • public abstract long getLedgerEndIndex()
    獲取 Leader 下一條日誌寫入的下標(最新日誌的下標)。
  • public abstract long getLedgerBeginIndex()
    獲取 Leader 第一條消息的下標。
  • public void updateCommittedIndex(long term, long committedIndex)
    更新commitedIndex的值,爲空實現,由具體的存儲子類實現。
  • protected void updateLedgerEndIndexAndTerm()
    更新 Leader 維護的 ledgerEndIndex 和 ledgerEndTerm 。
  • public void flush()
    刷寫,空方法,由具體子類實現。
  • public long truncate(DLedgerEntry entry, long leaderTerm, String leaderId)
    刪除日誌,空方法,由具體子類實現。
  • public void startup()
    啓動存儲管理器,空方法,由具體子類實現。
  • public void shutdown()
    關閉存儲管理器,空方法,由具體子類實現。

1.2 DLedgerMemoryStore

Dledger 基於內存實現的日誌存儲。

1.3 DLedgerMmapFileStore

基於文件內存映射機制的存儲實現。其核心屬性如下:

  • long ledgerBeginIndex = -1
    日誌的起始索引,默認爲 -1。
    l- ong ledgerEndIndex = -1
    下一條日誌下標,默認爲 -1。
  • long committedIndex = -1
    已提交的日誌索引。
  • long ledgerEndTerm
    當前最大的投票輪次。
  • DLedgerConfig dLedgerConfig
    DLedger 的配置信息。
  • MemberState memberState
    狀態機。
  • MmapFileList dataFileList
    日誌文件(數據文件)的內存映射Queue。
  • MmapFileList indexFileList
    索引文件的內存映射文件集合。(可對標 RocketMQ MappedFIleQueue )。
  • ThreadLocal< ByteBuffer> localIndexBuffer
    本地線程變量,用來緩存索引ByteBuffer。
  • ThreadLocal< ByteBuffer> localEntryBuffer
    本地線程變量,用來緩存數據索引ByteBuffer。
  • FlushDataService flushDataService
    數據文件刷盤線程。
  • CleanSpaceService cleanSpaceService
    清除過期日誌文件線程。
  • boolean isDiskFull = false
    磁盤是否已滿。
  • long lastCheckPointTimeMs
    上一次檢測點(時間戳)。
  • AtomicBoolean hasLoaded
    是否已經加載,主要用來避免重複加載(初始化)日誌文件。
  • AtomicBoolean hasRecovered
    是否已恢復。

2、DLedger 存儲 對標 RocketMQ 存儲

存儲部分主要包含存儲映射文件、消息存儲格式、刷盤、文件加載與文件恢復、過期文件刪除等,由於這些內容在 RocketMQ 存儲部分都已詳細介紹,故本文點到爲止,其對應的參考映射如下:
在這裏插入圖片描述
在 RocketMQ 中使用 MappedFile 來表示一個物理文件,而在 DLedger 中使用 DefaultMmapFIle 來表示一個物理文件。

在 RocketMQ 中使用 MappedFile 來表示多個物理文件(邏輯上連續),而在 DLedger 中則使用MmapFileList。

在 RocketMQ 中使用 DefaultMessageStore 來封裝存儲邏輯,而在 DLedger 中則使用DLedgerMmapFileStore來封裝存儲邏輯。

在 RocketMQ 中使用 Commitlog$FlushCommitLogService 來實現 commitlog 文件的刷盤,而在 DLedger 中則使用DLedgerMmapFileStore$FlushDataService來實現文件刷盤。

在 RocketMQ 中使用 DefaultMessageStore$CleanCommitlogService 來實現 commitlog 過期文件的刪除,而 DLedger 中則使用 DLedgerMmapFileStore$CleanSpaceService來實現。

由於其實現原理相同,上述部分已經在《RocketMQ 技術內幕》第4章中詳細剖析,故這裏就不重複分析了。

3、DLedger 數據存儲格式

在這裏插入圖片描述
存儲格式字段的含義如下:

  • magic
    魔數,4字節。
  • size
    條目總長度,包含 Header(協議頭) + 消息體,佔4字節。
  • entryIndex
    當前條目的 index,佔8字節。
  • entryTerm
    當前條目所屬的 投票輪次,佔8字節。
  • pos
    該條目的物理偏移量,類似於 commitlog 文件的物理偏移量,佔8字節。
  • channel
    保留字段,當前版本未使用,佔4字節。
  • chain crc
    當前版本未使用,佔4字節。
  • body crc
    body 的 CRC 校驗和,用來區分數據是否損壞,佔4字節。
  • body size
    用來存儲 body 的長度,佔4個字節。
  • body
    具體消息的內容。

源碼參考點:DLedgerMmapFileStore#recover、DLedgerEntry、DLedgerEntryCoder。

4、DLedger 索引存儲格式

在這裏插入圖片描述
即一個索引條目佔32個字節。

5、思考

DLedger 存儲相關就介紹到這裏,爲了與大家增加互動,特提出如下兩個思考題,歡迎與作者互動,這些問題將在該系列的後面文章專題探討。

1、DLedger 如果整合 RocketMQ 中的 commitlog 文件,使之支持多副本?
2、從老版本如何升級到新版本,需要考慮哪些因素呢?

尊敬的讀者朋友們,都閱讀到這裏了,麻煩幫忙點個贊鼓勵一下我,謝謝。


作者介紹:丁威,《RocketMQ技術內幕》作者,RocketMQ 社區佈道師,公衆號:中間件興趣圈 維護者,目前已陸續發表源碼分析Java集合、Java 併發包(JUC)、Netty、Mycat、Dubbo、RocketMQ、Mybatis等源碼專欄。可以點擊鏈接加入中間件知識星球 ,一起探討高併發、分佈式服務架構,交流源碼。

在這裏插入圖片描述

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