RocketMQ中的訊息存盤在本地檔案系統中,這些相關檔案默認在當前用戶主目錄下的store目錄中,

- abort:該檔案在Broker啟動后會自動創建,正常關閉Broker,該檔案會自動消失,若在沒有啟動Broker的情況下,發現這個檔案是存在的,則說明之前Broker的關閉是非正常關閉,
- checkpoint:其中存盤著commitlog、consumequeue、index檔案的最后刷盤時間戳
- commitlog:其中存放著commitlog檔案,而訊息是寫在commitlog檔案中的
- config:存放著Broker運行期間的一些配置資料
- consumequeue:其中存放著consumequeue檔案,佇列就存放在這個目錄中
- index:其中存放著訊息索引檔案indexFile
- lock:運行期間使用到的全域資源鎖
1 commitlog檔案
說明:在很多資料中commitlog目錄中的檔案簡單就稱為commitlog檔案,但在原始碼中,該檔案
被命名為mappedFile,
目錄與檔案
commitlog目錄中存放著很多的mappedFile檔案,當前Broker中的所有訊息都是落盤到這些
mappedFile檔案中的,mappedFile檔案大小為1G(小于等于1G),檔案名由20位十進制數構成,表示
當前檔案的第一條訊息的起始位移偏移量,
第一個檔案名一定是20位0構成的,因為第一個檔案的第一條訊息的偏移量commitlog offset為0
當第一個檔案放滿時,則會自動生成第二個檔案繼續存放訊息,假設第一個檔案大小是
1073741820位元組(1G = 1073741824位元組),則第二個檔案名就是00000000001073741824,
以此類推,第n個檔案名應該是前n-1個檔案大小之和,
一個Broker中所有mappedFile檔案的commitlog offset是連續的
需要注意的是,一個Broker中僅包含一個commitlog目錄,所有的mappedFile檔案都是存放在該目錄中
的,即無論當前Broker中存放著多少Topic的訊息,這些訊息都是被順序寫入到了mappedFile檔案中
的,也就是說,這些訊息在Broker中存放時并沒有被按照Topic進行分類存放,
mappedFile檔案是順序讀寫的檔案,所有其訪問效率很高
無論是SSD磁盤還是SATA磁盤,通常情況下,順序存取效率都會高于隨機存取,
訊息單元

mappedFile檔案內容由一個個的訊息單元構成,每個訊息單元中包含訊息總長度MsgLen、訊息的物理
位置physicalOffset、訊息體內容Body、訊息體長度BodyLength、訊息主題Topic、Topic長度
TopicLength、訊息生產者BornHost、訊息發送時間戳BornTimestamp、訊息所在的佇列QueueId、消
息在Queue中存盤的偏移量QueueOffset等近20余項訊息相關屬性,
需要注意到,訊息單元中是包含Queue相關屬性的,所以,我們在后續的學習中,就需要十分
留意commitlog與queue間的關系是什么?一個mappedFile檔案中第m+1個訊息單元的commitlog offset偏移量
L(m+1) = L(m) + MsgLen(m) (m >= 0)
2 consumequeue

目錄與檔案

為了提高效率,會為每個Topic在~/store/consumequeue中創建一個目錄,目錄名為Topic名稱,在該
Topic目錄下,會再為每個該Topic的Queue建立一個目錄,目錄名為queueId,每個目錄中存放著若干
consumequeue檔案,consumequeue檔案是commitlog的索引檔案,可以根據consumequeue定位到具
體的訊息,
consumequeue檔案名也由20位數字構成,表示當前檔案的第一個索引條目的起始位移偏移量,與
mappedFile檔案名不同的是,其后續檔案名是固定的,因為consumequeue檔案大小是固定不變的,
索引條目

每個consumequeue檔案可以包含30w個索引條目,每個索引條目包含了三個訊息重要屬性:訊息在
mappedFile檔案中的偏移量CommitLog Offset、訊息長度、訊息Tag的hashcode值,這三個屬性占20
個位元組,所以每個檔案的大小是固定的30w * 20位元組,
一個consumequeue檔案中所有訊息的Topic一定是相同的,但每條訊息的Tag可能是不同的
3. 對檔案的讀寫

訊息寫入
一條訊息進入到Broker后經歷了以下幾個程序才最終被持久化,
- Broker根據queueId,獲取到該訊息對應索引條目要在consumequeue目錄中的寫入偏移量,即
QueueOffset - 將queueId、queueOffset等資料,與訊息一起封裝為訊息單元
- 將訊息單元寫入到commitlog
- 同時,形成訊息索引條目
- 將訊息索引條目分發到相應的consumequeue
訊息拉取
當Consumer來拉取訊息時會經歷以下幾個步驟:
-
Consumer獲取到其要消費訊息所在Queue的消費偏移量offset ,計算出其要消費訊息的
訊息offset消費offset即消費進度,consumer對某個Queue的消費offset,即消費到了該Queue的第幾
條訊息
訊息offset = 消費offset + 1 -
Consumer向Broker發送拉取請求,其中會包含其要拉取訊息的Queue、訊息offset及訊息
Tag, -
Broker計算在該consumequeue中的queueOffset,
queueOffset = 訊息offset * 20位元組
- 從該queueOffset處開始向后查找第一個指定Tag的索引條目,
- 決議該索引條目的前8個位元組,即可定位到該訊息在commitlog中的commitlog offset
- 從對應commitlog offset中讀取訊息單元,并發送給Consumer
性能提升
RocketMQ中,無論是訊息本身還是訊息索引,都是存盤在磁盤上的,其不會影響訊息的消費嗎?當然
不會,其實RocketMQ的性能在目前的MQ產品中性能是非常高的,因為系統通過一系列相關機制大大
提升了性能,
首先,RocketMQ對檔案的讀寫操作是通過mmap零拷貝進行的,將對檔案的操作轉化為直接對記憶體地
址進行操作,從而極大地提高了檔案的讀寫效率,
其次,consumequeue中的資料是順序存放的,還引入了PageCache的預讀取機制,使得對
consumequeue檔案的讀取幾乎接近于記憶體讀取,即使在有訊息堆積情況下也不會影響性能,
PageCache機制,頁快取機制,是OS對檔案的快取機制,用于加速對檔案的讀寫操作,一般來
說,程式對檔案進行順序讀寫的速度幾乎接近于記憶體讀寫速度,主要原因是由于OS使用
PageCache機制對讀寫訪問操作進行性能優化,將一部分的記憶體用作PageCache,
- 寫操作:OS會先將資料寫入到PageCache中,隨后會以異步方式由pdflush(page dirty flush)
內核執行緒將Cache中的資料刷盤到物理磁盤- 讀操作:若用戶要讀取資料,其首先會從PageCache中讀取,若沒有命中,則OS在從物理磁
盤上加載該資料到PageCache的同時,也會順序對其相鄰資料塊中的資料進行預讀取,
RocketMQ中可能會影響性能的是對commitlog檔案的讀取,因為對commitlog檔案來說,讀取訊息時
會產生大量的隨機訪問,而隨機訪問會嚴重影響性能,不過,如果選擇合適的系統IO調度演算法,比如
設定調度演算法為Deadline(采用SSD固態硬碟的話),隨機讀的性能也會有所提升,
4 與Kafka的對比
RocketMQ的很多思想來源于Kafka,其中commitlog與consumequeue就是,
RocketMQ中的commitlog目錄與consumequeue的結合就類似于Kafka中的partition磁區目錄,
mappedFile檔案就類似于Kafka中的segment段,
Kafka中的Topic的訊息被分割為一個或多個partition,partition是一個物理概念,對應到系統上
就是topic目錄下的一個或多個目錄,每個partition中包含的檔案稱為segment,是具體存放訊息
的檔案,
Kafka中訊息存放的目錄結構是:topic目錄下有partition目錄,partition目錄下有segment檔案
Kafka中沒有二級分類標簽Tag這個概念
Kafka中無需索引檔案,因為生產者是將訊息直接寫在了partition中的,消費者也是直接從
partition中讀取資料的
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/299750.html
標籤:其他
上一篇:蘋果開啟了UWB上下游成熟的大門
下一篇:ESP8266學習——UART
