1.RocketMQ存儲概要設計
RocketMQ主要存儲的文件包括Comitlog文件、ConsumeQueue文件、IndexFIle文件。RocketMQ將所有主題的消息存儲在同一個文件中,確保消息發送時順序寫文件,盡最大的能力確保消息發送的高性能與吞吐量。但由於消息中間件一般是訂閱機制,這樣便給按照消息主題檢索帶來了極大的不便。爲了提高效率,RocketMQ引入了ConsumeQueu消息隊列文件,每個消息主題包含多個消息消費隊列,每一個消息隊列有一個消息文件。IndexFile索引文件,主要設計理念就是加速消息的檢索性能,根據消息的屬性快速從CommitLog文件中檢索消息
1.1: commitLog:消息存儲文件,所有消息主題的消息都存儲在CommitLog文件中。
1.2 ConsumeQueue:消息消費隊列,消息到達CommitLog文件後,將異步轉發到消息消費隊列,供消息消費者消費。
1.3 IndexFile:消息索引文件,主要存儲消息key與Offset的對應關係
1.4 事物狀態服務:存儲每條消息的事物狀態
1.5 定時消息服務:每一個延遲級別對應一個消息消費隊列,存儲延遲隊列的消息拉取進度。
2.功能描述
Broker是處理消息存儲,轉發等處理的服務器。
1.Broker以group分開,每個group只允許一個master,若干個slave。
2.只有master才能進行寫入操作,slave不允許。
3.slave從master中同步數據,同步策略取決於master的配置,可以採用同步雙寫,異步複製兩種。
4.客戶端消費可以從master和slave消費。在默認情況下,消費者都從master消費,在master掛後,客戶端由於從Name Server
中感知到Broker掛掉,就會從salve消費。
5.Broker向所有的Name Server節點建立長鏈接,註冊Topic 信息。
3.消息發送存儲流程
代碼結構:
消息存儲實現類:
在store模塊中:
org.apache.rocketmq.store.DefaultMessageStore
這個類在存儲模塊中最重要的一個類:
下面列舉一下核心屬性和方法
1. MessageStoreConfig messageStoreConfig :消息存儲配置屬性
2.CommitLog commitLog:CommitLog文件的存儲實現類
3.ConcurrentMap<String /**topic */,ConcurrentMap<Integer/*queueId*/,Conssume-Queue>> consumeQueueTable:消息隊列存儲緩存表,按消息主體分組。
4.FlusConsumeQueueService flushConsumeQueueService :消息隊列文件ConsumeQueue刷盤線程。
5. CleanCommitLogService cleanCommitLogService:清除CommitLog文件服務
6.CleanConsumeQueueService cleanConsumeQueueService :清除ConsumeQueue文件服務
7.IndexService indexService :索引文件實現類
8.AllocateMappedFileSErvice allocateMApppedFileService:MappedFile分配服務。
9.ReputMessageServie reputMessageService: CommitLog消息分發,根據CommitLog文件構建ConsumeQueue、IndexFile文件
10.HAService haService:存儲HA機制
11.TransientStorePool transientStorePool: 消息堆內存緩存
12.MessageArrivingListener messagArrivingListener: 消息拉取長輪訓模式消息達到監聽器。
13.BrokerConfig brokerConfig :Broker配置屬性。
14.StoreCheckpoint storeCheckPoint:文件刷盤監測點
15.LinkedList<CommitLogDispacher> dispatcherList:CommitLog文件轉發請求。
消息存儲追蹤入口:
org.apache.rocketmq.store.DefaultMessageStore#putMessage
注意事項:
master節點允許寫入,消息主體長度不能超過256個字符,消息屬性成都不能超過65536個字符。
第二步:
如果消息的延遲級別大於0,將消息的原主題名稱與原消息隊列ID存入消息屬性中,用延遲消息主體SCHEDULE_TOPIC,消息隊列ID更新原消息的主題與隊列,這個是併發消息消費重試關鍵的一步。
代碼中有關於延遲時間的判斷
第三步:
獲取當前可以寫入Commitlog文件,RocketMQ物理文件如下圖:
Commitlog文件存儲目錄爲${ROCKETMQ_HOME}/store/commitlog目錄,mac系統下面可以在用戶根目錄下面找store文件夾
每個文件默認1G,一個文件寫滿後,會再創建另外一個,以該文件中第一個偏移量爲文件名稱,偏移量小於20位用0補齊。如上圖第一個文件的偏移量爲0。MappedFileQueue可以看做是${ROCKETMQ_HOME}/store/commitlog文件夾,而MappedFile則對應該文件夾下一個個的文件。
第四步:
在寫入Commitlog之前,先申請鎖,消息存儲到CommitLog文件是串行的。
第五步:
設置消息的存儲時間,如果mappedFile爲空,表明${ROCKETMQ_HOME}/store/commitlog目錄下不存在任何文件,說明本次消息是第一次消息發送,用偏移量0創建第一個commit文件,。文件名:00000000000000000000
第六步:
將消息追加到MappedFile中。
第七步:
創建全局唯一消息ID,消息ID有16字節
4字節IP:4字節端口號:8字節消息偏移量
第八步:
獲取改消息在消息隊列的偏移量。CommitLog中保存了當前所有消息隊列的當前待寫入偏移量。
第九步:
根據消息體的長度、主體的長度、屬性的長度結合消息存儲格式計算消息的總長度。
第十步:
如果消息長度+END_FILE_MIN_BLAK_LENGTH大於CommitLog文件的空閒空間,則返回AppendMessageStatus.END_OF_FILE,Broker會重新創建一個新的CommitLog文件來存儲該消息。從這裏可以看出,每個CommitLog文件最少會空閒8個字節,高4字節存儲當前文件剩餘空間,低4字節存儲魔數:CommitLog.BLANK_MAGIC_CODE
十一步:
將消息內容存儲到ByteBuffer中,然後創建AppendMessageResult。這一步只是將消息存儲在MappedFile對應的內存映射Buffer中,並沒有刷寫到磁盤。
十二步:
更新消息隊列邏輯偏移量
十三步:
處理完消息追加邏輯後將釋放putMessageLock鎖。
後續會分析:存儲文件組織與內存映射機制
參考資料:《RocketMQ技術內幕》