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