Rocketmq学习1——Rocketmq架构&消息存储&刷盘机制
系列文章目錄和關于我
一丶什么是Rocketmq
RocketMQ是一款開源的分布式消息中間件,由阿里巴巴團隊最初開發,并于2016年貢獻給Apache軟件基金會,后成為Apache*項目。RocketMQ設計用于處理高并發、高吞吐量的場景,支持豐富的消息交互模式。
以下是RocketMQ的一些關鍵特性:
- 分布式架構:RocketMQ采用分布式集群架構,包含多個Broker服務器和NameServer。NameServer用于維護Broker節點和Topic路由信息,而Broker負責儲存和轉發消息。
- 消息可靠性和高性能:RocketMQ提供高可靠性的消息傳輸保證,如消息持久化、消費者消息確認機制和容錯機制。同時,它也注重高吞吐量的性能優化。
- 多種消息模型支持:RocketMQ支持多種消息傳遞模式,包括同步發送、異步發送和單向發送,也支持廣播和集群消費模式。
- 順序消息和延遲消息:RocketMQ支持嚴格的消息順序和可配置的延遲消息傳遞。
- 事務消息:RocketMQ支持事務性消息,允許在分布式系統中進行事務操作而不丟失消息。
- 多語言客戶端:提供多種語言的客戶端,如Java、C++、Go等,方便不同開發環境中的集成。
- 高度可擴展:RocketMQ通過水平擴展Broker和NameServer節點來支持更大規模的系統。
- 多租戶和多命名空間:RocketMQ支持多租戶操作,每個租戶可以有獨立的命名空間,方便資源隔離和管理。
- 監控和運維工具:提供了豐富的監控和運維工具,幫助管理和監控集群狀態。
RocketMQ適用于大規模的分布式系統,廣泛運用于實時消息處理、日志聚合、流數據處理、事務性消息傳遞等場景。由于其高性能和可靠性,它常被用于電商、金融、物聯網、大數據等行業。
二丶部署架構與領域模型
1.架構
- NameServer:獨立的命名服務,用于管理Broker服務器,是一個幾乎無狀態節點,可集群部署,節點之間無任何信息同步。
- Broker部署相對復雜,Broker分為Master與Slave,一個Master可以對應多個Slave,但是一個Slave只能對應一個Master,Master與Slave的對應關系通過指定相同的BrokerName和不同的BrokerId來定義,BrokerId為0 表示Master,非0表示Slave。Master也可以部署多個。每個Broker與Name Server集群中的所有節點建立長連接,定時注冊Topic信息到所有Name Server。
- Producer與Name Server集群中的其中一個節點(隨機選擇)建立長連接,定期從Name Server獲取Topic路由信息,并向提供Topic服務的Master建立長連接,且定時向Master發送心跳。Producer完全無狀態,可集群部署。
- Consumer與Name Server集群中的其中一個節點(隨機選擇)建立長連接,定期從Name Server獲取Topic路由信息,并向提供Topic服務的Master、Slave建立長連接,且定時向Master、Slave發送心跳。
在rocketmq的架構中,【無狀態】是非常巧妙的點,無狀態具備諸多優點:
- 可伸縮性:無狀態節點可以輕松地進行水平擴展(Scale Out),因為沒有狀態信息需要同步。新的節點可以隨時添加到系統中,而不需擔心現有狀態的遷移問題。
- 負載均衡:由于每個節點之間是相互獨立的,負載均衡器可以簡單地將請求分配給任何一個節點,無需考慮節點間的狀態同步,這樣可以更有效地分散負載。
- 容錯性:在無狀態架構中,若某個節點失敗,其他節點可以無縫接管處理請求,因為所有節點都是等效的,沒有持久狀態的依賴。這簡化了故障恢復流程。
- 簡化設計:無狀態設計通常更加簡單,因為開發者無需管理和同步跨多個節點的狀態,降低了處理分布式數據一致性的復雜性。
- 部署靈活性:無狀態服務可以在任何時間被部署在任何機器上,不需要考慮狀態信息的遷移和同步問題,使得自動化部署更為簡單
2.領域模型
- Producer:消息生產者,負責創建和發送消息到消息服務器。在RocketMQ中,生產者將消息發送到指定的Topic。
- Consumer:消息消費者,負責從消息服務器接收消息。消費者可以以推(Push)或拉(Pull)的方式獲取消息,并處理這些消息。
- Topic:消息主題,生產者將消息發布到特定的Topic,而消費者則從Topic訂閱消息。Topic是消息分類的邏輯概念,用于區分不同類型或用途的消息。
- MessageQueue:消息隊列,是消息的物理載體。在RocketMQ中,一個Topic可以分成多個Queue,這些Queue位于不同的Broker上,以支持并行處理和負載均衡。
- Subscription Group:訂閱組,是邏輯上的消費者分組。在這個分組內部,消費者實例通常以負載均衡的方式來消費消息
三丶消息隊列的使用場景
消息隊列(Message Queue,MQ)是一種在消息的傳輸過程中保存消息的容器,它被廣泛應用于系統解耦、異步消息、流量削峰等場景。以下是一些常見的消息隊列使用場景和用途:
- 異步處理:當前端系統提交任務后,不需要同步等待任務完成,而是通過消息隊列異步處理,提高了系統的響應速度。
- 系統解耦:在微服務或分布式架構中,各服務之間可以通過消息隊列進行通信,而不是直接調用,減少了服務間的依賴性。
- 流量削峰:在高流量事件如秒殺或促銷期間,通過消息隊列對請求進行緩存,防止瞬間大流量沖擊數據庫。
- 負載均衡:消息隊列可以平均分配任務給各個工作節點處理,使得任務處理更加均勻和高效。
- 日志處理:日志信息可以實時發送到消息隊列中,由后臺服務進行異步處理,如日志收集、分析和存儲。
- 數據同步:在多個系統或組件之間使用消息隊列同步數據,確保數據的一致性。
- 集成異構系統:消息隊列可以作為不同系統或應用之間的中介,實現平臺無關性的數據交換。
四丶消息存儲機制
上圖描述了rocketmq的消息存儲機制:
-
CommitLog:消息主體以及元數據的存儲主體,存儲Producer端寫入的消息主體內容。單個文件大小默認1G ,文件名長度為20位,左邊補零,剩余為起始偏移 量,比如00000000000000000000代表了第一個文件,起始偏移量為0,文件大小為 1G=1073741824;當第一個文件寫滿了,第二個文件為00000000001073741824,起始偏 移量為1073741824,以此類推。
在一個broker上面多個topic的消息都使用同一個commitLog進行存儲,這樣做的好處是:
- 順序寫盤:由于所有消息都追加到同一個文件,RocketMQ的消息寫入操作可以充分利用順序IO的優勢,這比隨機寫入具有更高的效率。并且不會出現多個topic搶占io資源的情況
- 簡化設計:這種全局的CommitLog設計簡化了消息存儲的復雜性,開發者無需為每個Topic管理獨立的文件或文件集。
- 易于擴展:共用一個CommitLog文件使得在消息量增長時,RocketMQ能夠方便地通過添加更多的Broker節點來擴展系統的消息寫入能力,而不需要對每個Topic進行單獨的調整。
然而,這種設計也意味著,當消費者需要讀取特定Topic的消息時,不能直接從CommitLog讀取,因為CommitLog中包含了來自所有Topic的消息。為了解決這個問題,RocketMQ引入了另外兩個重要的組件:ConsumerQueue和IndexFile。
-
ConsumerQueue:
RocketMQ是基于主題topic的訂閱模式,消息消費是針對主題進行 如果要遍歷commitlog文件根據topic檢索消息是非常低效。 Consumer即可根據ConsumeQueue來查找待消費的消息。 其中,ConsumeQueue(邏輯消費隊列)作為消費消息的索引:
- 保存了指定Topic下的隊列消息在CommitLog中的起始物理偏移量offset
- 消息大小size
- 消息Tag的HashCode值。
并且ConsumerQueue中存儲的內容是定長的,
這樣設計的好處是,當消息消費者拉取消息的時候,broker可用使用內存映射的方式將文件映射到內存中的某一個區域,避免內核空間和用戶空間的來回拷貝。
另外ConsumerQueue中存儲了消息tag的hash值,消費者訂閱消息的時候可指定tag(如:tagA || tagB)broker會根據這些條件,對ConsumerQueue中的內容進行過濾,然后再將commitLog中真正的內容讀取返回給消費者,但是hash是存在沖突可能性的,消費者需要根據消息中的tag進一步過濾。這個tag過濾機制減少了網絡資源的浪費!
-
IndexFile:索引文件提供了一種可以通過key或時間區間來查詢消息的方法。固定的單個IndexFile文件大小約為400M,一個IndexFile可以保存 2000W個索引,IndexFile的底層存儲設計為在文件系統中實現HashMap結構,故RocketMQ的索引文件其底層實現為hash索引。
隨口一句基于文件的hash索引,看似很簡單,但是其實這里還是有很多難點的:例如總不能一口氣讀完文件到內存序列化成hashMap然后進行索引吧。如下是rocketmq indexFile的設計:
40 Byte 的Header用于保存一些總的統計信息,4*500W的 Slot Table并不保存真正的索引數據,而是保存每個槽位對應的單向鏈表的頭。20*2000W 是真正的索引數據,即一個 Index File 可以保存 2000W個索引。
這樣的設計在進行索引的時候可用先根據hash取模得到Slot內容,然后根據slot得到對應鏈表的偏移,然后在索引中每一個元素都記錄上一個元素的偏移,從而實現遍歷。
這個過程并不需要讀取所有文件內容到內存,只需使用內存映射MappedByteBuffer按需讀取即可!
五丶刷盤機制
不只是rocketmq ,很多中間件都有同步刷盤和異步刷盤
RocketMQ 的刷盤機制是確保消息持久化,以避免進程崩潰或系統故障導致數據丟失的重要手段。RocketMQ 提供了兩種刷盤模式:
-
同步刷盤(SYNC_FLUSH):
在這種模式下,每當生產者發送消息并得到Broker的響應之前,消息都會被立即寫入磁盤(CommitLog文件)。這提供了*別的持久化保證,但犧牲了一定的吞吐量與延遲性能。具體過程如下:
- 消息被發送到Broker。
- Broker將消息追加到內存中的CommitLog(預寫日志緩沖區)。
- Broker會等待直到CommitLog數據被實際寫入磁盤(fileChannel.force(true))。
- 消息成功寫入磁盤后,Broker給生產者發送確認響應。
- 這種模式下,如果在消息確認寫入磁盤前系統崩潰,消息不會丟失。
-
異步刷盤(ASYNC_FLUSH):
在這種模式下,消息先寫入內存映射文件(MappedByteBuffer),然后Broker會在未來的某個時間點異步將數據刷寫到磁盤。異步刷盤模式提供了更好的性能和吞吐量,但在Broker進程崩潰或系統故障時,可能會丟失最近寫入的一些消息。具體過程如下:
- 消息被發送到Broker。
- Broker將消息追加到內存中的CommitLog(內存映射文件區)。
- Broker直接給生產者發送確認響應(不等待數據實際寫入磁盤)。
- 內存中的數據將定期通過另外的刷盤線程或操作系統的頁緩存機制異步寫入磁盤。
- 在這種模式下,如果Broker崩潰,那么還未被刷寫到磁盤的消息可能會丟失。
在刷盤策略的選擇上,需根據具體業務的數據持久化要求和性能需求進行權衡。如果對數據安全性要求極高,可以選擇同步刷盤,如果對性能有較高要求,可以選擇異步刷盤。RocketMQ 默認使用的是異步刷盤模式。
總結
以上是生活随笔為你收集整理的Rocketmq学习1——Rocketmq架构&消息存储&刷盘机制的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 踩坑ffmpeg录制的mp4无法在浏览器
- 下一篇: .NET周刊 【12月第3期 2023-