【Java进阶营】阿里架构师加持,十分钟入门RocketMQ,就是这么简单
本文首先引出消息中間件通常需要解決哪些問題,在解決這些問題當(dāng)中會遇到什么困難,Apache RocketMQ作為阿里開源的一款高性能、高吞吐量的分布式消息中間件否可以解決,規(guī)范中如何定義這些問題。然后本文將介紹RocketMQ的架構(gòu)設(shè)計,以期讓讀者快速了解RocketMQ。
一、消息中間件需要解決哪些問題?
1. Publish/Subscribe
發(fā)布訂閱是消息中間件的最基本功能,也是相對于傳統(tǒng)RPC通信而言。在此不再詳述。
2. Message Priority
規(guī)范中描述的優(yōu)先級是指在一個消息隊列中,每條消息都有不同的優(yōu)先級,一般用整數(shù)來描述,優(yōu)先級高的消息先投遞,如果消息完全在一個內(nèi)存隊列中,那么在投遞前可以按照優(yōu)先級排序,令優(yōu)先級高的先投遞。
由于RocketMQ所有消息都是持久化的,所以如果按照優(yōu)先級來排序,開銷會非常大,因此RocketMQ沒有特意支持消息優(yōu)先級,但是可以通過變通的方式實現(xiàn)類似功能,即單獨配置一個優(yōu)先級高的隊列,和一個普通優(yōu)先級的隊列, 將不同優(yōu)先級發(fā)送到不同隊列即可。
對于優(yōu)先級問題,可以歸納為2類:
3. Message Order
消息有序指的是一類消息消費時,能按照發(fā)送的順序來消費。例如:一個訂單產(chǎn)生了3條消息,分別是訂單創(chuàng)建,訂單付款,訂單完成。消費時,要按照這個順序消費才能有意義。但是同時訂單之間是可以并行消費的。
RocketMQ可以嚴(yán)格的保證消息有序。
4. Message Filter
①. Broker端消息過濾
在Broker中,按照Consumer的要求做過濾,優(yōu)點是減少了對于Consumer無用消息的網(wǎng)絡(luò)傳輸。
缺點是增加了Broker的負(fù)擔(dān),實現(xiàn)相對復(fù)雜。
②. Consumer端消息過濾
這種過濾方式可由應(yīng)用完全自定義實現(xiàn),但是缺點是很多無用的消息要傳輸?shù)紺onsumer端。
5. Message Persistence
消息中間件通常采用的幾種持久化方式:
JMS與CORBA Notification規(guī)范沒有明確說明如何持久化,但是持久化部分的性能直接決定了整個消息中間件的性能。
RocketMQ充分利用Linux文件系統(tǒng)內(nèi)存cache來提高性能。
6. Message Reliablity
影響消息可靠性的幾種情況:
(1)、(2)、(3)、(4)四種情況都屬于硬件資源可立即恢復(fù)情況,RocketMQ在這四種情況下能保證消息不丟,或者丟失少量數(shù)據(jù)(依賴刷盤方式是同步還是異步)。
(5)、(6)屬于單點故障,且無法恢復(fù),一旦發(fā)生,在此單點上的消息全部丟失。RocketMQ在這兩種情況下,通過異步復(fù)制,可保證99%的消息不丟,但是仍然會有極少量的消息可能丟失。通過同步雙寫技術(shù)可以完全避免單點,同步雙寫勢必會影響性能,適合對消息可靠性要求極高的場合,例如與Money相關(guān)的應(yīng)用。
RocketMQ從3.0版本開始支持同步雙寫。
7. Low Latency Messaging
在消息不堆積情況下,消息到達(dá)Broker后,能立刻到達(dá)Consumer。
RocketMQ使用長輪詢Pull方式,可保證消息非常實時,消息實時性不低于Push。
8. At least Once
是指每個消息必須投遞一次。
RocketMQ Consumer先pull消息到本地,消費完成后,才向服務(wù)器返回ack,如果沒有消費一定不會ack消息,所以RocketMQ可以很好的支持此特性。
9. Exactly Only Once
發(fā)送消息階段,不允許發(fā)送重復(fù)的消息。
消費消息階段,不允許消費重復(fù)的消息。
只有以上兩個條件都滿足情況下,才能認(rèn)為消息是“Exactly Only Once”,而要實現(xiàn)以上兩點,在分布式系統(tǒng)環(huán)境下,不可避免要產(chǎn)生巨大的開銷。所以RocketMQ為了追求高性能,并不保證此特性,要求在業(yè)務(wù)上進(jìn)行去重,也就是說消費消息要做到冪等性。RocketMQ雖然不能嚴(yán)格保證不重復(fù),但是正常情況下很少會出現(xiàn)重復(fù)發(fā)送、消費情況,只有網(wǎng)絡(luò)異常,Consumer啟停等異常情況下會出現(xiàn)消息重復(fù)。
二、Broker的Buffer滿了怎么辦?
Broker的Buffer通常指的是Broker中一個隊列的內(nèi)存Buffer大小,這類Buffer通常大小有限,如果Buffer滿了以后怎么辦?
下面是CORBA Notification規(guī)范中處理方式:
- AnyOrder - Any event may be discarded on overflow.
- This is the default setting for this property.
- FifoOrder - The first event received will be the first discarded.
- LifoOrder - The last event received will be the first discarded.
- PriorityOrder - Events should be discarded in priority order, such that lower priority events will be discarded before higher priority events.
- DeadlineOrder - Events should be discarded in the order of shortest expiry deadline first
RocketMQ沒有內(nèi)存Buffer概念,RocketMQ的隊列都是持久化磁盤,數(shù)據(jù)定期清除。
對于此問題的解決思路,RocketMQ同其他MQ有非常顯著的區(qū)別,RocketMQ的內(nèi)存Buffer抽象成一個無限長度的隊列,不管有多少數(shù)據(jù)進(jìn)來都能裝得下,這個無限是有前提的,Broker會定期刪除過期的數(shù)據(jù),例如Broker只保存3天的消息,那么這個Buffer雖然長度無限,但是3天前的數(shù)據(jù)會被從隊尾刪除。
此問題的本質(zhì)原因是網(wǎng)絡(luò)調(diào)用存在不確定性,即既不成功也不失敗的第三種狀態(tài),所以才產(chǎn)生了消息重復(fù)性問題。
三、回溯消費
回溯消費是指Consumer已經(jīng)消費成功的消息,由于業(yè)務(wù)上需求需要重新消費,要支持此功能,Broker在向Consumer投遞成功消息后,消息仍然需要保留。并且重新消費一般是按照時間維度,例如由于Consumer系統(tǒng)故障,恢復(fù)后需要重新消費1小時前的數(shù)據(jù),那么Broker要提供一種機(jī)制,可以按照時間維度來回退消費進(jìn)度。
RocketMQ支持按照時間回溯消費,時間維度精確到毫秒,可以向前回溯,也可以向后回溯。
四、消息堆積
消息中間件的主要功能是異步解耦,還有個重要功能是擋住前端的數(shù)據(jù)洪峰,保證后端系統(tǒng)的穩(wěn)定性,這就要求消息中間件具有一定的消息堆積能力,消息堆積分以下兩種情況:
評估消息堆積能力主要有以下四點:
五、分布式事務(wù)
已知的幾個分布式事務(wù)規(guī)范,如XA,JTA等。其中XA規(guī)范被各大數(shù)據(jù)庫廠商廣泛支持,如Oracle,Mysql等。其中XA的TM實現(xiàn)佼佼者如Oracle Tuxedo,在金融、電信等領(lǐng)域被廣泛應(yīng)用。
分布式事務(wù)涉及到兩階段提交問題,在數(shù)據(jù)存儲方面的方面必然需要KV存儲的支持,因為第二階段的提交回滾需要修改消息狀態(tài),一定涉及到根據(jù)Key去查找Message的動作。RocketMQ在第二階段繞過了根據(jù)Key去查找Message的問題,采用第一階段發(fā)送Prepared消息時,拿到了消息的Offset,第二階段通過Offset去訪問消息,并修改狀態(tài),Offset就是數(shù)據(jù)的地址。
RocketMQ這種實現(xiàn)事務(wù)方式,沒有通過KV存儲做,而是通過Offset方式,存在一個顯著缺陷,即通過Offset更改數(shù)據(jù),會令系統(tǒng)的臟頁過多,需要特別關(guān)注。
六、定時消息
定時消息是指消息發(fā)到Broker后,不能立刻被Consumer消費,要到特定的時間點或者等待特定的時間后才能被消費。
如果要支持任意的時間精度,在Broker層面,必須要做消息排序,如果再涉及到持久化,那么消息排序要不可避免的產(chǎn)生巨大性能開銷。
RocketMQ支持定時消息,但是不支持任意時間精度,支持特定的level,例如定時5s,10s,1m等。
七、消息重試
Consumer消費消息失敗后,要提供一種重試機(jī)制,令消息再消費一次。Consumer消費消息失敗通常可以認(rèn)為有以下幾種情況:
由于消息本身的原因,例如反序列化失敗,消息數(shù)據(jù)本身無法處理(例如話費充值,當(dāng)前消息的手機(jī)號被注銷,無法充值)等。這種錯誤通常需要跳過這條消息,再消費其他消息,而這條失敗的消息即使立刻重試消費,99%也不成功,所以最好提供一種定時重試機(jī)制,即過10s秒后再重試。
由于依賴的下游應(yīng)用服務(wù)不可用,例如db連接不可用,外系統(tǒng)網(wǎng)絡(luò)不可達(dá)等。遇到這種錯誤,即使跳過當(dāng)前失敗的消息,消費其他消息同樣也會報錯。這種情況建議應(yīng)用sleep 30s,再消費下一條消息,這樣可以減輕Broker重試消息的壓力。在此我向大家推薦一個架構(gòu)學(xué)習(xí)交流圈。交流學(xué)習(xí)指導(dǎo)偽鑫:1253431195(里面有大量的面試題及答案)里面會分享一些資深架構(gòu)師錄制的視頻錄像:有Spring,MyBatis,Netty源碼分析,高并發(fā)、高性能、分布式、微服務(wù)架構(gòu)的原理,JVM性能優(yōu)化、分布式架構(gòu)等這些成為架構(gòu)師必備的知識體系。還能領(lǐng)取免費的學(xué)習(xí)資源,目前受益良多
八、RocketMQ Overview
RocketMQ是否解決了上述消息中間件面臨的問題,接下來讓我們一探究竟。
1. RocketMQ 是什么?
上圖是一個典型的消息中間件收發(fā)消息的模型,RocketMQ也是這樣的設(shè)計,簡單說來,RocketMQ具有以下特點:
是一個隊列模型的消息中間件,具有高性能、高可靠、高實時、分布式特點。
Producer、Consumer、隊列都可以分布式。
Producer向一些隊列輪流發(fā)送消息,隊列集合稱為Topic,Consumer如果做廣播消費,則一個consumer實例消費這個Topic對應(yīng)的所有隊列,如果做集群消費,則多個Consumer實例平均消費這個topic對應(yīng)的隊列集合。
2. RocketMQ 物理部署結(jié)構(gòu)
如上圖所示, RocketMQ的部署結(jié)構(gòu)有以下特點:
Name Server是一個幾乎無狀態(tài)節(jié)點,可集群部署,節(jié)點之間無任何信息同步。
Broker部署相對復(fù)雜,Broker分為Master與Slave,一個Master可以對應(yīng)多個Slave,但是一個Slave只能對應(yīng)一個Master,Master與Slave的對應(yīng)關(guān)系通過指定相同的BrokerName,不同的BrokerId來定義,BrokerId為0表示Master,非0表示Slave。Master也可以部署多個。每個Broker與Name Server集群中的所有節(jié)點建立長連接,定時注冊Topic信息到所有Name Server。
Producer與Name Server集群中的其中一個節(jié)點(隨機(jī)選擇)建立長連接,定期從Name Server取Topic路由信息,并向提供Topic服務(wù)的Master建立長連接,且定時向Master發(fā)送心跳。Producer完全無狀態(tài),可集群部署。
Consumer與Name Server集群中的其中一個節(jié)點(隨機(jī)選擇)建立長連接,定期從Name Server取Topic路由信息,并向提供Topic服務(wù)的Master、Slave建立長連接,且定時向Master、Slave發(fā)送心跳。Consumer既可以從Master訂閱消息,也可以從Slave訂閱消息,訂閱規(guī)則由Broker配置決定。
3. RocketMQ 邏輯部署結(jié)構(gòu)
如上圖所示,RocketMQ的邏輯部署結(jié)構(gòu)有Producer和Consumer兩個特點。
①. Producer Group
用來表示一個發(fā)送消息應(yīng)用,一個Producer Group下包含多個Producer實例,可以是多臺機(jī)器,也可以是一臺機(jī)器的多個進(jìn)程,或者一個進(jìn)程的多個Producer對象。一個Producer Group可以發(fā)送多個Topic消息,Producer Group作用如下:
標(biāo)識一類Producer
可以通過運維工具查詢這個發(fā)送消息應(yīng)用下有多個Producer實例
發(fā)送分布式事務(wù)消息時,如果Producer中途意外宕機(jī),Broker會主動回調(diào)Producer Group內(nèi)的任意一臺機(jī)器來確認(rèn)事務(wù)狀態(tài)。
②. Consumer Group
用來表示一個消費消息應(yīng)用,一個Consumer Group下包含多個Consumer實例,可以是多臺機(jī)器,也可以是多個進(jìn)程,或者是一個進(jìn)程的多個Consumer對象。一個Consumer Group下的多個Consumer以均攤方式消費消息,如果設(shè)置為廣播方式,那么這個Consumer Group下的每個實例都消費全量數(shù)據(jù)。
4. RocketMQ 數(shù)據(jù)存儲結(jié)構(gòu)
如上圖所示,RocketMQ采取了一種數(shù)據(jù)與索引分離的存儲方法。有效降低文件資源、IO資源,內(nèi)存資源的損耗。即便是阿里這種海量數(shù)據(jù),高并發(fā)場景也能夠有效降低端到端延遲,并具備較強(qiáng)的橫向擴(kuò)展能力。
總結(jié)
以上是生活随笔為你收集整理的【Java进阶营】阿里架构师加持,十分钟入门RocketMQ,就是这么简单的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: JavaScript isArray
- 下一篇: Compiz Fusion 安装后的设置