目錄
@(本節目錄)
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等源碼專欄。可以點擊鏈接加入中間件知識星球 ,一起探討高併發、分佈式服務架構,交流源碼。