RocketMQ:消息存儲

通常來說我們對分佈式隊列有高可靠性的要求,所以數據要進行持久化存儲。

在這裏插入圖片描述

  1. 消息生產者發送消息到MQ。
  2. MQ收到消息,將消息進行持久化,即在存儲系統中新增一條記錄。
  3. 返回ACK確認消息給生產者。
  4. 然後MQ推送消息給對應的消費者,等待消費者返回ACK。
  5. 如果消息消費者在指定時間內成功返回ACK,那麼MQ認爲消息消費成功,在存儲系統中刪除消息,即執行第6步;如果MQ在指定時間內沒有收到ACK,則認爲消息消費失敗,會嘗試重新推送消息,重複執行4、5、6步驟。

1. 存儲介質

  • 關係型數據庫DB

存儲系統可選用JDBC的方式來做消息持久化,通過簡單的xml配置信息即可實現JDBC消息存儲。由於普通關係型數據庫(如Mysql)在單表數據量達到千萬級別的情況下,其IO讀寫性能往往會出現瓶頸。在可靠性方面,該種方案非常依賴DB,如果一旦DB出現故障,則MQ的消息就無法落盤存儲會導致線上故障。

  • 文件系統

目前業界較爲常用的幾款產品(RocketMQ/Kafka/RabbitMQ)均採用的是消息刷盤至所部署虛擬機/物理機的文件系統來做持久化(刷盤一般可以分爲異步刷盤和同步刷盤兩種模式)。消息刷盤爲消息存儲提供了一種高效率、高可靠性和高性能的數據持久化方式。除非部署MQ機器本身或是本地磁盤掛了,否則一般是不會出現無法持久化的故障問題。

性能對比:文件系統>關係型數據庫DB

2. 消息的存儲和發送

2.1 消息存儲

目前的高性能磁盤,順序寫速度可以達到600MB/s, 超過了一般網卡的傳輸速度。但是磁盤隨機寫的速度只有大概100KB/s,和順序寫的性能相差6000倍!因爲有如此巨大的速度差別,好的消息隊列系統會比普通的消息隊列系統速度快多個數量級。RocketMQ的消息用順序寫,保證了消息存儲的速度。

2.2 消息發送

Linux操作系統分爲【用戶態】和【內核態】,文件操作、網絡操作需要涉及這兩種形態的切換,免不了進行數據複製。

一臺服務器把本機磁盤文件的內容發送到客戶端,一般分爲兩個步驟:

1)read:讀取本地文件內容;

2)write:將讀取的內容通過網絡發送出去。

這兩個看似簡單的操作,實際進行了4 次數據複製,分別是:

  1. 從磁盤複製數據到內核態內存;
  2. 從內核態內存複製到用戶態內存;
  3. 然後從用戶態內存複製到網絡驅動的內核態內存;
  4. 最後是從網絡驅動的內核態內存復 制到網卡中進行傳輸。

在這裏插入圖片描述

通過使用mmap的方式,可以省去向【用戶態】的內存複製,提高速度。這種機制在Java中是通過MappedByteBuffer實現的。

RocketMQ充分利用了上述特性,也就是所謂的“零拷貝”技術,提高消息存盤和網絡發送的速度。

這裏需要注意的是,採用MappedByteBuffer這種內存映射的方式有幾個限制,其中之一是一次只能映射1.5~2G 的文件至用戶態的虛擬內存,這也是爲何RocketMQ默認設置單個CommitLog日誌數據文件爲1G的原因了。

3. 消息存儲結構

RocketMQ消息的存儲是由ConsumeQueue和CommitLog配合完成的,消息真正的物理存儲文件是CommitLog,ConsumeQueue是消息的邏輯隊列,類似數據庫的索引文件,存儲的是指向物理存儲的地址。每 個Topic下的每個Message Queue都有一個對應的ConsumeQueue文件。

在這裏插入圖片描述

  • CommitLog:存儲消息的元數據。
  • ConsumerQueue:存儲消息在CommitLog的索引。
  • IndexFile:爲了消息查詢提供了一種通過key或時間區間來查詢消息的方法,這種通過IndexFile來查找消息的方法不影響發送與消費消息的主流程。

4. 刷盤機制

RocketMQ的消息是存儲到磁盤上的,這樣既能保證斷電後恢復, 又可以讓存儲的消息量超出內存的限制。RocketMQ爲了提高性能,會盡可能地保證磁盤的順序寫。消息在通過Producer寫入RocketMQ的時候,有兩種寫磁盤方式,分佈式同步刷盤和異步刷盤。

在這裏插入圖片描述

4.1 同步刷盤

在返回寫成功狀態時,消息已經被寫入磁盤。具體流程是,消息寫入內存的PAGECACHE後,立刻通知刷盤線程刷盤, 然後等待刷盤完成,刷盤線程執行完成後喚醒等待的線程,返回消息寫成功的狀態。

提醒:還記得在《Redis:持久化之AOF》中我們也說到,由於操作系統的緩存機制,數據並沒有真正地立即寫入磁盤,而是進入系統的磁盤緩存。

4.2 異步刷盤

在返回寫成功狀態時,消息可能只是被寫入了內存的PAGECACHE,寫操作的返回快,吞吐量大;當內存裏的消息量積累到一定程度時,統一觸發寫磁盤動作,快速寫入。

4.3 配置

不管是同步刷盤還是異步刷盤,都是通過Broker配置文件裏的flushDiskType參數設置的,這個參數被配置成SYNC_FLUSH、ASYNC_FLUSH中的 一個。

——End——
更多精彩分享,可掃碼關注微信公衆號哦。

在這裏插入圖片描述

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