天天看點

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

RocketMQ DLedger 的存儲實作思路與 RocketMQ 的存儲實作思路相似,本文就不再從源碼角度詳細剖析其實作,隻是點出其實作關鍵點。我們不妨簡單回顧一下 CommitLog 檔案、ConsumeQueue 檔案設計思想。

其檔案組成形式如下:

源碼分析 RocketMQ DLedger 多副本存儲實作
正如上圖所示,多個 commitlog 檔案組成一個邏輯上的連續檔案,使用 MappedFileQueue 表示,單個 commitlog 檔案使用 MappedFile 表示。

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

1、DLedger 存儲相關類圖

源碼分析 RocketMQ 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 DLedger 多副本存儲實作

在 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 資料存儲格式

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

存儲格式字段的含義如下:

  • magic

    魔數,4位元組。

  • size

    條目總長度,包含 Header(協定頭) + 消息體,占4位元組。

  • entryIndex

    目前條目的 index,占8位元組。

  • entryTerm

    目前條目所屬的 投票輪次,占8位元組。

  • pos

    該條目的實體偏移量,類似于 commitlog 檔案的實體偏移量,占8位元組。

  • channel

    保留字段,目前版本未使用,占4位元組。

  • chain crc

    目前版本未使用,占4位元組。

  • body crc
  1. 的 CRC 校驗和,用來區分資料是否損壞,占4位元組。
  • body size

    用來存儲 body 的長度,占4個位元組。

  • body

    具體消息的内容。

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

4、DLedger 索引存儲格式

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

即一個索引條目占32個位元組。

5、思考

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

1、DLedger 如果整合 RocketMQ 中的 commitlog 檔案,使之支援多副本?

2、從老版本如何更新到新版本,需要考慮哪些因素呢?

原文釋出時間為:2019-09-01

本文作者:丁威,《RocketMQ技術内幕》作者。

本文來自

中間件興趣圈

,了解相關資訊可以關注