- 消息存儲:因?yàn)榉植际疥?duì)列有高可靠性的要求,所以數(shù)據(jù)要進(jìn)行持久化存儲流昏。
- 消息生產(chǎn)到消費(fèi)的整個流程:
- 消息生產(chǎn)者發(fā)送消息到MQ扎即;
- MQ收到消息吞获,將消息持久化,在存儲中新增一條記錄谚鄙;
- 返回ACK給生產(chǎn)者各拷;
- MQ push 消息給對應(yīng)的消費(fèi)者,然后等待消費(fèi)者返回ACK闷营;
- 若消息消費(fèi)者在指定時間內(nèi)成功返回ack烤黍,則MQ認(rèn)為消息消費(fèi)成功,在存儲中刪除消息傻盟,即執(zhí)行第6步速蕊;否則認(rèn)為消息消費(fèi)失敗,會嘗試重新push消息娘赴,重復(fù)執(zhí)行第4规哲、5、6步驟诽表。
- 消息持久化的存儲介質(zhì):
-
關(guān)系型數(shù)據(jù)庫DB
:Apache下開源的另外一款MQ——ActiveMQ(默認(rèn)采用的KahaDB做消息存儲)可選用JDBC的方式來做消息持久化唉锌,通過簡單的xml配置信息即可實(shí)現(xiàn)JDBC消息存儲。由于普通關(guān)系型數(shù)據(jù)庫(如:Mysql)在單表數(shù)據(jù)量達(dá)到千萬級別的情況下竿奏,其IO讀寫性能往往會出現(xiàn)瓶頸袄简。在可靠性方面,該種方案非常依賴DB泛啸,若一旦DB出現(xiàn)故障绿语,則MQ的消息無法落盤存儲將導(dǎo)致線上發(fā)生故障。 -
文件系統(tǒng)
:目前業(yè)界較為常用的幾款MQ產(chǎn)品(RocketMQ/Kafka/RabbitMQ)均采用的是消息刷盤至所部署虛擬機(jī)/物理機(jī)的文件系統(tǒng)來做持久化(刷盤一般可以分為異步刷盤
和同步刷盤
兩種模式)平痰。消息刷盤為消息存儲提供了一種高效率汞舱、高可靠性和高性能的數(shù)據(jù)持久化方式。除非部署MQ的機(jī)器本身或本地磁盤掛了宗雇,否則一般是不會出現(xiàn)無法持久化的故障問題昂芜。 - 性能對比:文件系統(tǒng)>關(guān)系型數(shù)據(jù)庫DB。
-
- 消息存儲:若磁盤使用得當(dāng)赔蒲,則其速度完全可以匹配上網(wǎng)絡(luò)數(shù)據(jù)的傳輸速度泌神。目前高性能磁盤的順序?qū)懰俣瓤梢赃_(dá)到600MB/s, 超過了一般網(wǎng)卡的傳輸速度舞虱。但磁盤隨機(jī)寫的速度大概只有100KB/s欢际,和順序?qū)懙男阅芟嗖?000倍!RocketMQ的消息使用
順序?qū)?/code>矾兜,保證了消息的存儲速度损趋。
- 消息發(fā)送:Linux 操作系統(tǒng)分為用戶態(tài)和內(nèi)核態(tài),文件操作椅寺、網(wǎng)絡(luò)操作需要涉及這兩種形態(tài)的切換浑槽,避免不了進(jìn)行數(shù)據(jù)復(fù)制蒋失。一臺服務(wù)器把本機(jī)磁盤文件的內(nèi)容發(fā)送到客戶端,一般分為兩個步驟:①read:讀取本地文件內(nèi)容桐玻;②write:將讀取的內(nèi)容通過網(wǎng)絡(luò)發(fā)送出去篙挽。這兩個看似簡單的操作,實(shí)際上進(jìn)行了4 次數(shù)據(jù)復(fù)制镊靴,分別是:
- 從磁盤復(fù)制數(shù)據(jù)到內(nèi)核態(tài)內(nèi)存铣卡;
- 從內(nèi)核態(tài)內(nèi)存復(fù)制數(shù)據(jù)到用戶態(tài)內(nèi)存;
- 從用戶態(tài)內(nèi)存復(fù)制數(shù)據(jù)到網(wǎng)絡(luò)驅(qū)動的內(nèi)核態(tài)內(nèi)存偏竟;
- 從網(wǎng)絡(luò)驅(qū)動的內(nèi)核態(tài)內(nèi)存復(fù)制到網(wǎng)卡中進(jìn)行網(wǎng)絡(luò)傳輸煮落。
- 通過使用共享內(nèi)存mmap的方式,省去了向用戶態(tài)的內(nèi)存復(fù)制操作苫耸,提高了拷貝速度州邢。這種機(jī)制在Java中是通過
MappedByteBuffer
來實(shí)現(xiàn)的儡陨。RocketMQ充分利用了上述特性褪子,也就是所謂的零拷貝
技術(shù),提高了消息存盤和網(wǎng)絡(luò)發(fā)送的速度骗村。注意:采用MappedByteBuffer
這種內(nèi)存映射的方式有幾個限制嫌褪,其中之一是一次只能映射1.5~2G
的文件至用戶態(tài)的虛擬內(nèi)存,這也是為何RocketMQ默認(rèn)設(shè)置單個CommitLog
日志數(shù)據(jù)文件為1G
的原因了胚股。
- 消息的存儲結(jié)構(gòu):由
ConsumeQueue
和CommitLog
配合完成 的笼痛,消息真正的物理存儲文件是CommitLog
,ConsumeQueue
是消息的邏輯隊(duì)列琅拌,類似數(shù)據(jù)庫的索引文件缨伊,存儲的是指向物理存儲的地址。每個Topic下的每個Message Queue
都有一個對應(yīng)的ConsumeQueue
文件进宝。 -
CommitLog
:存儲消息的元數(shù)據(jù)刻坊。 -
ConsumerQueue
:存儲消息在CommitLog的索引。 -
IndexFile
:通過key
或時間區(qū)間
來查詢消息党晋,且該過程不影響發(fā)送與消費(fèi)消息的主流程谭胚。
- 刷盤機(jī)制:分布式
同步刷盤
和異步刷盤
。-
同步刷盤
:在返回寫成功狀態(tài)時未玻,消息已被寫入磁盤灾而。具體流程是:消息寫入內(nèi)存的PAGECACHE
頁緩存后,立刻通知刷盤線程刷盤扳剿,待刷盤完成后喚醒等待的線程旁趟,返回消息寫成功的狀態(tài)。 -
異步刷盤
:在返回寫成功狀態(tài)時庇绽,消息可能只是被寫入了內(nèi)存的PAGECACHE
頁緩存锡搜,寫操作返回快癣猾,吞吐量大;當(dāng)內(nèi)存里的消息量積累到一定程度時余爆,統(tǒng)一觸發(fā)寫磁盤動作纷宇,快速寫入。 - 采用同步刷盤還是異步刷盤蛾方?將Broker配置文件里的
flushDiskType
參數(shù)設(shè)置為SYNC_FLUSH
像捶,ASYNC_FLUSH
中的一個即可。
-
- RocketMQ分布式集群是通過Master和Slave的配合達(dá)到高可用性的桩砰。
- Master和Slave的區(qū)別:在Broker的配置文件中拓春,參數(shù) brokerId的值為0表明這個Broker是Master,大于0表明這個Broker是 Slave亚隅,同時brokerRole參數(shù)也會說明這個Broker是Master還是Slave啄育。
- Master角色的Broker支持讀和寫旺聚,Slave角色的Broker僅支持讀,也就是 Producer只能和Master角色的Broker連接寫入消息;Consumer可以連接 Master角色的Broker和Slave角色的Broker來讀取消息址貌。
- 消息發(fā)送高可用:在創(chuàng)建Topic時乡摹,把Topic的多個Message Queue創(chuàng)建在多個Broker組上(相同Broker名稱弱匪,不同 brokerId的機(jī)器組成一個Broker組)畔裕,這樣當(dāng)一個Broker組的Master不可用后,其它組的Master仍然可用酿联,Producer仍然可以發(fā)送消息终息。RocketMQ目前還不支持把Slave自動轉(zhuǎn)成Master,若機(jī)器資源不足贞让,且需要把Slave轉(zhuǎn)成Master周崭,則要手動停止Slave角色的Broker,更改配置文件喳张,用新的配置文件啟動Broker续镇。
- 消息消費(fèi)高可用:在Consumer的配置文件中,并不需要設(shè)置是從Master讀還是從Slave 讀蹲姐,當(dāng)Master不可用或繁忙時磨取,Consumer會被自動切換到從Slave 讀。有了自動切換Consumer這種機(jī)制柴墩,當(dāng)一個Master角色的機(jī)器出現(xiàn)故障后忙厌,Consumer仍然可以從Slave讀取消息,不影響Consumer程序江咳。這就達(dá)到了消費(fèi)端的高可用性逢净。