RocketMQ 是什么
Github 上關(guān)于 RocketMQ 的介紹:
RcoketMQ 是一款低延遲鬼癣、高可靠凡桥、可伸縮、易于使用的消息中間件僵闯。具有以下特性:
- 支持發(fā)布/訂閱(Pub/Sub)和點(diǎn)對(duì)點(diǎn)(P2P)消息模型
- 在一個(gè)隊(duì)列中可靠的先進(jìn)先出(FIFO)和嚴(yán)格的順序傳遞
- 支持拉(pull)和推(push)兩種消息模式
- 單一隊(duì)列百萬消息的堆積能力
- 支持多種消息協(xié)議霜大,如 JMS围橡、MQTT 等
- 分布式高可用的部署架構(gòu),滿足至少一次消息傳遞語(yǔ)義
- 提供 docker 鏡像用于隔離測(cè)試和云集群部署
- 提供配置、指標(biāo)和監(jiān)控等功能豐富的 Dashboard
專業(yè)術(shù)語(yǔ)
Producer
消息生產(chǎn)者榄融,生產(chǎn)者的作用就是將消息發(fā)送到 MQ参淫,生產(chǎn)者本身既可以產(chǎn)生消息,如讀取文本信息等愧杯。也可以對(duì)外提供接口涎才,由外部應(yīng)用來調(diào)用接口,再由生產(chǎn)者將收到的消息發(fā)送到 MQ民效。
Producer Group
生產(chǎn)者組憔维,簡(jiǎn)單來說就是多個(gè)發(fā)送同一類消息的生產(chǎn)者稱之為一個(gè)生產(chǎn)者組。在這里可以不用關(guān)心畏邢,只要知道有這么一個(gè)概念即可业扒。
Consumer
消息消費(fèi)者,簡(jiǎn)單來說舒萎,消費(fèi) MQ 上的消息的應(yīng)用程序就是消費(fèi)者程储,至于消息是否進(jìn)行邏輯處理,還是直接存儲(chǔ)到數(shù)據(jù)庫(kù)等取決于業(yè)務(wù)需要臂寝。
Consumer Group
消費(fèi)者組章鲤,和生產(chǎn)者類似,消費(fèi)同一類消息的多個(gè) consumer 實(shí)例組成一個(gè)消費(fèi)者組咆贬。
Topic
Topic 是一種消息的邏輯分類败徊,比如說你有訂單類的消息,也有庫(kù)存類的消息掏缎,那么就需要進(jìn)行分類皱蹦,一個(gè)是訂單 Topic 存放訂單相關(guān)的消息,一個(gè)是庫(kù)存 Topic 存儲(chǔ)庫(kù)存相關(guān)的消息眷蜈。
Message
Message 是消息的載體沪哺。一個(gè) Message 必須指定 topic,相當(dāng)于寄信的地址酌儒。Message 還有一個(gè)可選的 tag 設(shè)置辜妓,以便消費(fèi)端可以基于 tag 進(jìn)行過濾消息。也可以添加額外的鍵值對(duì),例如你需要一個(gè)業(yè)務(wù) key 來查找 broker 上的消息籍滴,方便在開發(fā)過程中診斷問題酪夷。
Tag
標(biāo)簽可以被認(rèn)為是對(duì) Topic 進(jìn)一步細(xì)化。一般在相同業(yè)務(wù)模塊中通過引入標(biāo)簽來標(biāo)記不同用途的消息异逐。
Broker
Broker 是 RocketMQ 系統(tǒng)的主要角色捶索,其實(shí)就是前面一直說的 MQ。Broker 接收來自生產(chǎn)者的消息灰瞻,儲(chǔ)存以及為消費(fèi)者拉取消息的請(qǐng)求做好準(zhǔn)備腥例。
Name Server
Name Server 為 producer 和 consumer 提供路由信息。
RocketMQ 架構(gòu)
由這張圖可以看到有四個(gè)集群酝润,分別是 NameServer 集群燎竖、Broker 集群、Producer 集群和 Consumer 集群:
- NameServer: 提供輕量級(jí)的服務(wù)發(fā)現(xiàn)和路由要销。 每個(gè) NameServer 記錄完整的路由信息构回,提供等效的讀寫服務(wù),并支持快速存儲(chǔ)擴(kuò)展疏咐。
- Broker: 通過提供輕量級(jí)的 Topic 和 Queue 機(jī)制來處理消息存儲(chǔ),同時(shí)支持推(push)和拉(pull)模式以及主從結(jié)構(gòu)的容錯(cuò)機(jī)制纤掸。
- Producer:生產(chǎn)者,產(chǎn)生消息的實(shí)例浑塞,擁有相同 Producer Group 的 Producer 組成一個(gè)集群借跪。
- Consumer:消費(fèi)者,接收消息進(jìn)行消費(fèi)的實(shí)例酌壕,擁有相同 Consumer Group 的
Consumer 組成一個(gè)集群掏愁。
簡(jiǎn)單說明一下圖中箭頭含義,從 Broker 開始卵牍,Broker Master1 和 Broker Slave1 是主從結(jié)構(gòu)果港,它們之間會(huì)進(jìn)行數(shù)據(jù)同步,即 Date Sync糊昙。同時(shí)每個(gè) Broker 與
NameServer 集群中的所有節(jié)
點(diǎn)建立長(zhǎng)連接辛掠,定時(shí)注冊(cè) Topic 信息到所有 NameServer 中。
Producer 與 NameServer 集群中的其中一個(gè)節(jié)點(diǎn)(隨機(jī)選擇)建立長(zhǎng)連接释牺,定期從 NameServer 獲取 Topic 路由信息萝衩,并向提供 Topic 服務(wù)的 Broker Master 建立長(zhǎng)連接,且定時(shí)向 Broker 發(fā)送心跳船侧。Producer 只能將消息發(fā)送到 Broker master欠气,但是 Consumer 則不一樣厅各,它同時(shí)和提供 Topic 服務(wù)的 Master 和 Slave
建立長(zhǎng)連接镜撩,既可以從 Broker Master 訂閱消息,也可以從 Broker Slave 訂閱消息。
RocketMQ 集群部署模式
單 master 模式
也就是只有一個(gè) master 節(jié)點(diǎn)袁梗,稱不上是集群宜鸯,一旦這個(gè) master 節(jié)點(diǎn)宕機(jī),那么整個(gè)服務(wù)就不可用遮怜,適合個(gè)人學(xué)習(xí)使用淋袖。
多 master 模式
多個(gè) master 節(jié)點(diǎn)組成集群,單個(gè) master 節(jié)點(diǎn)宕機(jī)或者重啟對(duì)應(yīng)用沒有影響锯梁。
優(yōu)點(diǎn):所有模式中性能最高
缺點(diǎn):?jiǎn)蝹€(gè) master 節(jié)點(diǎn)宕機(jī)期間即碗,未被消費(fèi)的消息在節(jié)點(diǎn)恢復(fù)之前不可用,消息的實(shí)時(shí)性就受到影響陌凳。
注意:使用同步刷盤可以保證消息不丟失剥懒,同時(shí) Topic 相對(duì)應(yīng)的 queue 應(yīng)該分布在集群中各個(gè)節(jié)點(diǎn),而不是只在某各節(jié)點(diǎn)上合敦,否則初橘,該節(jié)點(diǎn)宕機(jī)會(huì)對(duì)訂閱該 topic 的應(yīng)用造成影響。
多 master 多 slave 異步復(fù)制模式
在多 master 模式的基礎(chǔ)上充岛,每個(gè) master 節(jié)點(diǎn)都有至少一個(gè)對(duì)應(yīng)的 slave保檐。master
節(jié)點(diǎn)可讀可寫,但是 slave 只能讀不能寫崔梗,類似于 mysql 的主備模式夜只。
優(yōu)點(diǎn): 在 master 宕機(jī)時(shí),消費(fèi)者可以從 slave 讀取消息炒俱,消息的實(shí)時(shí)性不會(huì)受影響盐肃,性能幾乎和多 master 一樣。
缺點(diǎn):使用異步復(fù)制的同步方式有可能會(huì)有消息丟失的問題权悟。
多 master 多 slave 同步雙寫模式
同多 master 多 slave 異步復(fù)制模式類似砸王,區(qū)別在于 master 和 slave 之間的數(shù)據(jù)同步方式。
優(yōu)點(diǎn):同步雙寫的同步模式能保證數(shù)據(jù)不丟失峦阁。
缺點(diǎn):發(fā)送單個(gè)消息 RT 會(huì)略長(zhǎng)谦铃,性能相比異步復(fù)制低10%左右。
刷盤策略:同步刷盤和異步刷盤(指的是節(jié)點(diǎn)自身數(shù)據(jù)是同步還是異步存儲(chǔ))
同步方式:同步雙寫和異步復(fù)制(指的一組 master 和 slave 之間數(shù)據(jù)的同步)
注意:要保證數(shù)據(jù)可靠榔昔,需采用同步刷盤和同步雙寫的方式驹闰,但性能會(huì)較其他方式低。
消息類型
普通消息
普通消息也叫做無序消息撒会,簡(jiǎn)單來說就是沒有順序的消息嘹朗,producer 只管發(fā)送消息,consumer 只管接收消息诵肛,至于消息和消息之間的順序并沒有保證屹培,可能先發(fā)送的消息先消費(fèi),也可能先發(fā)送的消息后消費(fèi)。
舉個(gè)簡(jiǎn)單例子褪秀,producer 依次發(fā)送 order id 為 1蓄诽、2、3 的消息到 broker媒吗,consumer 接到的消息順序有可能是 1仑氛、2、3闸英,也有可能是 2锯岖、1、3 等情況甫何,這就是普通消息嚎莉。
因?yàn)椴恍枰WC消息的順序,所以消息可以大規(guī)模并發(fā)地發(fā)送和消費(fèi)沛豌,吞吐量很高趋箩,適合大部分場(chǎng)景。
有序消息
有序消息就是按照一定的先后順序的消息類型加派。
舉個(gè)例子來說叫确,producer 依次發(fā)送 order id 為 1、2芍锦、3 的消息到 broker竹勉,consumer 接到的消息順序也就是 1、2娄琉、3 次乓,而不會(huì)出現(xiàn)普通消息那樣的 2、1孽水、3 等情況票腰。
那么有序消息是如何保證的呢?我們都知道消息首先由 producer 到 broker女气,再?gòu)?broker 到 consumer杏慰,分這兩步走。那么要保證消息的有序炼鞠,勢(shì)必這兩步都是要保證有序的缘滥,即要保證消息是按有序發(fā)送到 broker,broker 也是有序?qū)⑾⑼哆f給 consumer谒主,兩個(gè)條件必須同時(shí)滿足朝扼,缺一不可。進(jìn)一步還可以將有序消息分成
- 全局有序消息
- 局部有序消息
之前我們講過霎肯,topic 只是消息的邏輯分類擎颖,內(nèi)部實(shí)現(xiàn)其實(shí)是由 queue 組成凹耙。當(dāng) producer 把消息發(fā)送到某個(gè) topic 時(shí),默認(rèn)是會(huì)消息發(fā)送到具體的 queue 上肠仪。
舉個(gè)例子,producer 發(fā)送 order id 為 1备典、2异旧、3、4 的四條消息到 topicA 上提佣,假設(shè) topicA 的 queue 數(shù)為 3 個(gè)(queue0吮蛹、queue1、queue2)拌屏,那么消息的分布可能就是這種情況潮针,id 為 1 的在 queue0,id 為 2 的在 queue1倚喂,id 為 3 的在 queue2每篷,id 為 4 的在 queue0。同樣的端圈,consumer 消費(fèi)時(shí)也是按 queue 去消費(fèi)焦读,這時(shí)候就可能出現(xiàn)先消費(fèi) 1、4舱权,再消費(fèi) 2矗晃、3,和我們的預(yù)期不符宴倍。那么我們?nèi)绾螌?shí)現(xiàn) 1张症、2、3鸵贬、4 的消費(fèi)順序呢俗他?道理其實(shí)很簡(jiǎn)單,只需要把訂單 topic 的 queue 數(shù)改為 1阔逼,如此一來拯辙,只要 producer 按照 1、2颜价、3涯保、4 的順序去發(fā)送消息,那么 consumer 自然也就按照 1周伦、2夕春、3、4 的順序去消費(fèi)专挪,這就是全局有序消息及志。
由于一個(gè) topic 只有一個(gè) queue 片排,即使我們有多個(gè) producer 實(shí)例和 consumer 實(shí)例也很難提高消息吞吐量。就好比過獨(dú)木橋速侈,大家只能一個(gè)挨著一個(gè)過去率寡,效率低下。
那么有沒有吞吐量和有序之間折中的方案呢倚搬?其實(shí)是有的冶共,就是局部有序消息。
我們知道訂單消息可以再細(xì)分為訂單創(chuàng)建每界、訂單付款捅僵、訂單完成等消息,這些消息都有相同的 order id眨层。同時(shí)庙楚,也只有按照訂單創(chuàng)建、訂單付款趴樱、訂單完成的順序去消費(fèi)才符合業(yè)務(wù)邏輯馒闷。但是不同 order id 的消息是可以并行的,不會(huì)影響到業(yè)務(wù)叁征。這時(shí)候就常見做法就是將 order id 進(jìn)行處理窜司,將 order id 相同的消息發(fā)送到 topicB 的同一個(gè) queue,假設(shè)我們 topicB 有 2 個(gè) queue航揉,那么我們可以簡(jiǎn)單的對(duì) id 取余塞祈,奇數(shù)的發(fā)往 queue0,偶數(shù)的發(fā)往 queue1帅涂,消費(fèi)者按照 queue 去消費(fèi)時(shí)议薪,就能保證 queue0 里面的消息有序消費(fèi),queue1 里面的消息有序消費(fèi)媳友。
由于一個(gè) topic 可以有多個(gè) queue斯议,所以在性能比全局有序高得多。假設(shè) queue 數(shù)是 n醇锚,理論上性能就是全局有序的 n 倍哼御,當(dāng)然 consumer 也要跟著增加才行。在實(shí)際情況中焊唬,這種局部有序消息是會(huì)比全局有序消息用的更多恋昼。
延時(shí)消息
延時(shí)消息,簡(jiǎn)單來說就是當(dāng) producer 將消息發(fā)送到 broker 后赶促,會(huì)延時(shí)一定時(shí)間后才投遞給 consumer 進(jìn)行消費(fèi)液肌。
RcoketMQ的延時(shí)等級(jí)為:1s,5s鸥滨,10s嗦哆,30s谤祖,1m,2m老速,3m粥喜,4m,5m橘券,6m额湘,7m,8m约郁,9m,10m但两,20m鬓梅,30m,1h谨湘,2h绽快。level=0,表示不延時(shí)紧阔。level=1坊罢,表示 1 級(jí)延時(shí),對(duì)應(yīng)延時(shí) 1s擅耽。level=2 表示 2 級(jí)延時(shí)活孩,對(duì)應(yīng)5s,以此類推乖仇。
這種消息一般適用于消息生產(chǎn)和消費(fèi)之間有時(shí)間窗口要求的場(chǎng)景憾儒。比如說我們網(wǎng)購(gòu)時(shí),下單之后是有一個(gè)支付時(shí)間乃沙,超過這個(gè)時(shí)間未支付起趾,系統(tǒng)就應(yīng)該自動(dòng)關(guān)閉該筆訂單。那么在訂單創(chuàng)建的時(shí)候就會(huì)就需要發(fā)送一條延時(shí)消息(延時(shí)15分鐘)后投遞給 consumer警儒,consumer 接收消息后再對(duì)訂單的支付狀態(tài)進(jìn)行判斷是否關(guān)閉訂單训裆。
設(shè)置延時(shí)非常簡(jiǎn)單,只需要在Message設(shè)置對(duì)應(yīng)的延時(shí)級(jí)別即可蜀铲。
消息發(fā)送方式
同步發(fā)送
簡(jiǎn)單來說边琉,同步發(fā)送就是指 producer 發(fā)送消息后,會(huì)在接收到 broker 響應(yīng)后才繼續(xù)發(fā)下一條消息的通信方式记劝。
由于這種同步發(fā)送的方式確保了消息的可靠性艺骂,同時(shí)也能及時(shí)得到消息發(fā)送的結(jié)果,故而適合一些發(fā)送比較重要的消息場(chǎng)景隆夯,比如說重要的通知郵件钳恕、營(yíng)銷短信等等别伏。在實(shí)際應(yīng)用中,這種同步發(fā)送的方式還是用得比較多的忧额。
異步發(fā)送
接著就是異步發(fā)送厘肮,異步發(fā)送是指 producer 發(fā)出一條消息后,不需要等待 broker 響應(yīng)睦番,就接著發(fā)送下一條消息的通信方式类茂。需要注意的是,不等待 broker 響應(yīng)托嚣,并不意味著 broker 不響應(yīng)巩检,而是通過回調(diào)接口來接收 broker 的響應(yīng)。所以要記住一點(diǎn)示启,異步發(fā)送同樣可以對(duì)消息的響應(yīng)結(jié)果進(jìn)行處理兢哭。
由于異步發(fā)送不需要等待 broker 的響應(yīng),故在一些比較注重 RT(響應(yīng)時(shí)間)的場(chǎng)景就會(huì)比較適用夫嗓。比如迟螺,在一些視頻上傳的場(chǎng)景,我們知道視頻上傳之后需要進(jìn)行轉(zhuǎn)碼舍咖,如果使用同步發(fā)送的方式來通知啟動(dòng)轉(zhuǎn)碼服務(wù)矩父,那么就需要等待轉(zhuǎn)碼完成才能發(fā)回轉(zhuǎn)碼結(jié)果的響應(yīng),由于轉(zhuǎn)碼時(shí)間往往較長(zhǎng)排霉,很容易造成響應(yīng)超時(shí)窍株。此時(shí),如果使用的是異步發(fā)送通知轉(zhuǎn)碼服務(wù)攻柠,那么就可以等轉(zhuǎn)碼完成后夹姥,再通過回調(diào)接口來接收轉(zhuǎn)碼結(jié)果的響應(yīng)了。
單向發(fā)送
單向發(fā)送辙诞,見名知意辙售,就是一種單方向通信方式,也就是說 producer 只負(fù)責(zé)發(fā)送消息飞涂,不等待 broker 發(fā)回響應(yīng)結(jié)果旦部,而且也沒有回調(diào)函數(shù)觸發(fā),這也就意味著 producer 只發(fā)送請(qǐng)求不等待響應(yīng)結(jié)果较店。
由于單向發(fā)送只是簡(jiǎn)單地發(fā)送消息士八,不需要等待響應(yīng),也沒有回調(diào)接口觸發(fā)梁呈,故發(fā)送消息所耗費(fèi)的時(shí)間非常短婚度,同時(shí)也意味著消息不可靠。所以這種單向發(fā)送比較適用于那些耗時(shí)要求非常短官卡,但對(duì)可靠性要求并不高的場(chǎng)景蝗茁,比如說日志收集醋虏。
下面通過一張表格,簡(jiǎn)單總結(jié)一下同步發(fā)送哮翘、異步發(fā)送和單向發(fā)送的特點(diǎn)颈嚼。
發(fā)送方式 | 發(fā)送TPS | 發(fā)送結(jié)果響應(yīng) | 可靠性 |
---|---|---|---|
同步發(fā)送 | 小 | 有 | 不丟失 |
異步發(fā)送 | 中 | 有 | 不丟失 |
單向發(fā)送 | 大 | 沒有 | 可能丟失 |
可以看到,從發(fā)送 TPS 來看饭寺,由于單向發(fā)送不需要等待響應(yīng)也沒有回調(diào)接口觸發(fā)阻课,發(fā)送速度非常快艰匙,一般都是微秒級(jí)的限煞,在消息體大小一樣的情況下,其發(fā)送 TPS 最大员凝。而同步發(fā)送署驻,需要等待響應(yīng)結(jié)果的返回,受網(wǎng)絡(luò)狀況的影響較大绊序,故發(fā)送 TPS 就比較小硕舆。異步發(fā)送不等待響應(yīng)結(jié)果秽荞,發(fā)送消息時(shí)幾乎不受網(wǎng)絡(luò)的影響骤公,故相比同步發(fā)送來說,其發(fā)送 TPS 要大得多扬跋。
關(guān)于可靠性阶捆,大家需要牢記前面提過的,異步發(fā)送并不意味著消息不可靠钦听,異步發(fā)送也是會(huì)接收到響應(yīng)結(jié)果洒试,也能對(duì)響應(yīng)結(jié)果進(jìn)行處理。即使發(fā)送失敗朴上,也可以通過一些補(bǔ)償手段進(jìn)行消息重發(fā)垒棋。和同步發(fā)送比起來,異步發(fā)送的發(fā)送 TPS 更大痪宰,更適合那些調(diào)用鏈路較長(zhǎng)的一些場(chǎng)景叼架。在實(shí)際使用中,同步發(fā)送和異步發(fā)送都是較為常用的兩種方式衣撬,大家要視具體業(yè)務(wù)場(chǎng)景進(jìn)行合理地選擇乖订。
消費(fèi)模式
首先明確一點(diǎn),RocketMQ 是基于發(fā)布訂閱模型的消息中間件具练。所謂的發(fā)布訂閱就是說乍构,consumer 訂閱了 broker 上的某個(gè) topic,當(dāng) producer 發(fā)布消息到 broker 上的該 topic 時(shí)扛点,consumer 就能收到該條消息哥遮。
之前我們講過 consumer group 的概念岂丘,即消費(fèi)同一類消息的多個(gè) consumer 實(shí)例組成一個(gè)消費(fèi)者組,也可以稱為一個(gè) consumer 集群昔善,這些 consumer 實(shí)例使用同一個(gè) group name元潘。需要注意一點(diǎn),除了使用同一個(gè) group name君仆,訂閱的 tag 也必須是一樣的翩概,只有符合這兩個(gè)條件的 consumer 實(shí)例才能組成 consumer 集群。
集群消費(fèi)
當(dāng) consumer 使用集群消費(fèi)時(shí)返咱,每條消息只會(huì)被 consumer 集群內(nèi)的任意一個(gè) consumer 實(shí)例消費(fèi)一次钥庇。舉個(gè)例子,當(dāng)一個(gè) consumer 集群內(nèi)有 3 個(gè)consumer 實(shí)例(假設(shè)為consumer 1咖摹、consumer 2评姨、consumer 3)時(shí),一條消息投遞過來萤晴,只會(huì)被consumer 1吐句、consumer 2、consumer 3中的一個(gè)消費(fèi)店读。
同時(shí)記住一點(diǎn)嗦枢,使用集群消費(fèi)的時(shí)候,consumer 的消費(fèi)進(jìn)度是存儲(chǔ)在 broker 上屯断,consumer 自身是不存儲(chǔ)消費(fèi)進(jìn)度的文虏。消息進(jìn)度存儲(chǔ)在 broker 上的好處在于,當(dāng)你 consumer 集群是擴(kuò)大或者縮小時(shí)殖演,由于消費(fèi)進(jìn)度統(tǒng)一在broker上氧秘,消息重復(fù)的概率會(huì)被大大降低了。
注意:在集群消費(fèi)模式下趴久,并不能保證每一次消息失敗重投都投遞到同一個(gè) consumer 實(shí)例丸相。
廣播消費(fèi)
當(dāng) consumer 使用廣播消費(fèi)時(shí),每條消息都會(huì)被 consumer 集群內(nèi)所有的 consumer 實(shí)例消費(fèi)一次彼棍,也就是說每條消息至少被每一個(gè) consumer 實(shí)例消費(fèi)一次灭忠。舉個(gè)例子,當(dāng)一個(gè) consumer 集群內(nèi)有 3 個(gè) consumer 實(shí)例(假設(shè)為 consumer 1滥酥、consumer 2更舞、consumer 3)時(shí),一條消息投遞過來坎吻,會(huì)被 consumer 1缆蝉、consumer 2、consumer 3都消費(fèi)一次。
與集群消費(fèi)不同的是刊头,consumer 的消費(fèi)進(jìn)度是存儲(chǔ)在各個(gè) consumer 實(shí)例上黍瞧,這就容易造成消息重復(fù)。還有很重要的一點(diǎn)原杂,對(duì)于廣播消費(fèi)來說印颤,是不會(huì)進(jìn)行消費(fèi)失敗重投的,所以在 consumer 端消費(fèi)邏輯處理時(shí)穿肄,需要額外關(guān)注消費(fèi)失敗的情況年局。
雖然廣播消費(fèi)能保證集群內(nèi)每個(gè) consumer 實(shí)例都能消費(fèi)消息,但是消費(fèi)進(jìn)度的維護(hù)咸产、不具備消息重投的機(jī)制大大影響了實(shí)際的使用矢否。因此,在實(shí)際使用中脑溢,更推薦使用集群消費(fèi)僵朗,因?yàn)榧合M(fèi)不僅擁有消費(fèi)進(jìn)度存儲(chǔ)的可靠性,還具有消息重投的機(jī)制屑彻。而且验庙,我們通過集群消費(fèi)也可以達(dá)到廣播消費(fèi)的效果。
使用集群消費(fèi)模擬廣播消費(fèi)
如果業(yè)務(wù)上確實(shí)需要使用廣播消費(fèi)社牲,那么我們可以通過創(chuàng)建多個(gè) consumer 實(shí)例粪薛,每個(gè) consumer 實(shí)例屬于不同的 consumer group,但是它們都訂閱同一個(gè) topic膳沽。舉個(gè)例子汗菜,我們創(chuàng)建 3 個(gè) consumer 實(shí)例让禀,consumer 1(屬于consumer group 1)挑社、consumer 2(屬于 consumer group 2)、consumer 3(屬于consumer group 3)巡揍,它們都訂閱了 topic A 痛阻,那么當(dāng) producer 發(fā)送一條消息到 topic A 上時(shí),由于 3 個(gè)consumer 屬于不同的 consumer group腮敌,所以 3 個(gè)consumer都能收到消息阱当,也就達(dá)到了廣播消費(fèi)的效果了。 除此之外糜工,每個(gè) consumer 實(shí)例的消費(fèi)邏輯可以一樣也可以不一樣弊添,每個(gè)consumer group還可以根據(jù)需要增加 consumer 實(shí)例,比起廣播消費(fèi)來說更加靈活捌木。
消息過濾
說到消息過濾油坝,就不得不說到 tag。沒錯(cuò),就是我們之前在專業(yè)術(shù)語(yǔ)中提到過的 tag澈圈。也稱為消息標(biāo)簽彬檀,用來標(biāo)記 Topic 下的不同用途的消息。
在 RocketMQ 中消費(fèi)者是可以按照 Tag 對(duì)消息進(jìn)行過濾瞬女。舉個(gè)電商交易場(chǎng)景的例子窍帝,用戶下完訂單之后,在后臺(tái)會(huì)產(chǎn)生一系列的消息诽偷,比如說訂單消息坤学、支付消息和物流消息。假設(shè)這些消息都發(fā)送到 Topic 為 Trade 中报慕,同時(shí)用 tag 為 order 來標(biāo)記訂單消息拥峦,用 tag 為 pay 來標(biāo)記支付消息,用 tag 為 logistics 來標(biāo)記物流消息卖子。需要支付消息的支付系統(tǒng)(相當(dāng)于一個(gè) consumer)訂閱 Trade 中 tag 為 pay 的消息略号,此時(shí),broker 則只會(huì)把 tag 為 pay 的消息投遞給支付系統(tǒng)洋闽。而如果是一個(gè)實(shí)時(shí)計(jì)算系統(tǒng)玄柠,它可能需要接收所有和交易相關(guān)的消息,那么只要它訂閱 Trade 中 tag 為 order诫舅、pay羽利、logistics 的消息,broker 就會(huì)把帶有這些 tag 的消息投遞給實(shí)時(shí)計(jì)算系統(tǒng)刊懈。
對(duì)于消息分類这弧,我們可以選擇創(chuàng)建多個(gè) Topic 來區(qū)分,也可以選擇在同一個(gè) Topic 下創(chuàng)建多個(gè) tag 來區(qū)分虚汛。這兩種方式都是可行的匾浪,但是一般情況下,不同的 Topic 之間的消息是沒有什么必然聯(lián)系的卷哩,使用 tag 來區(qū)分同一個(gè) Topic 下相互關(guān)聯(lián)的消息則更加合適一些蛋辈。
在實(shí)際使用中,消息過濾可以幫助我們只消費(fèi)我們所需要的消息将谊,這是在broker端就幫我們處理好的并淋,大大減少了在 consumer 端的消息過濾處理旗笔,一方面減少了代碼量碟婆,另一方面更減少了不必要消息的網(wǎng)絡(luò)傳輸消耗退腥。
消息重試
首先明確之前說過的,消息重試只針對(duì)集群消費(fèi)模式栋齿,廣播消費(fèi)沒有消息重試的特性苗胀,消費(fèi)失敗之后托酸,只會(huì)繼續(xù)消費(fèi)下一條消息。這也是為什么我們一再?gòu)?qiáng)調(diào)柒巫,推薦大家使用集群消費(fèi)模式励堡,其消息重試的特性能給開發(fā)者帶來極大的方便。
那么什么是消息重試呢堡掏?簡(jiǎn)單來說应结,就是當(dāng)消費(fèi)者消費(fèi)消息失敗后,broker 會(huì)重新投遞該消息泉唁,直到消費(fèi)成功鹅龄。在 RocketMQ 中,當(dāng)消費(fèi)者使用集群消費(fèi)模式時(shí)亭畜,消費(fèi)者接收到消息并進(jìn)行相應(yīng)的邏輯處理之后扮休,最后都要返回一個(gè)狀態(tài)值給 broker。這樣 broker 才知道是否消費(fèi)成功拴鸵,需不需要重新投遞消息玷坠。也就是說,我們可以通過設(shè)置返回的狀態(tài)值來告訴 broker 是否重新投遞消息劲藐。
到這里八堡,可能大家會(huì)有一個(gè)疑問,那如果這條消息本身就是一條臟數(shù)據(jù)聘芜,就算你消費(fèi) 100 次也不會(huì)消費(fèi)成功兄渺,難道還是一直去重試嘛?其實(shí) RocketMQ 并不會(huì)無限制地重試下去汰现,默認(rèn)每條消息最多重試 16 次挂谍,而每次重試的間隔時(shí)間如下表所示:
第幾次重試 | 每次重試間隔時(shí)間 |
---|---|
1 | 10 秒 |
2 | 30 秒 |
3 | 1 分鐘 |
4 | 2 分鐘 |
5 | 3 分鐘 |
6 | 4 分鐘 |
7 | 5 分鐘 |
8 | 6 分鐘 |
9 | 7 分鐘 |
10 | 8 分鐘 |
11 | 9 分鐘 |
12 | 10 分鐘 |
13 | 20 分鐘 |
14 | 30 分鐘 |
15 | 1 小時(shí) |
16 | 2 小時(shí) |
那么如果消息重試 16 次之后還是消費(fèi)失敗怎么辦呢?那么消息就不會(huì)再投遞給消費(fèi)者瞎饲,而是將消息放到相對(duì)應(yīng)的死信隊(duì)列中口叙。這時(shí)候我們就需要對(duì)死信隊(duì)列的消息做一些人工補(bǔ)償處理,因?yàn)檫@些消息可能本身就有問題企软,也有可能和消費(fèi)邏輯調(diào)用的服務(wù)有關(guān)等庐扫,所以需要人工判斷之后再進(jìn)行處理饭望。
到這里不知道大家有沒有一個(gè)疑問仗哨,那就是什么樣的情況才叫消費(fèi)失敗呢?可以分為 3 種情況:
- 返回 ConsumeConcurrentlyStatus.RECONSUME_LATER
- 返回 null
- 拋出異常
前兩種情況都比較好理解铅辞,就是前面說過的設(shè)置狀態(tài)值厌漂,也就是說,只需要消費(fèi)者返回 ConsumeConcurrentlyStatus.RECONSUME_LATER 或者 null斟珊,就相當(dāng)于告訴 broker 說苇倡,這條消息我消費(fèi)失敗了,你給我重新投遞一次。而對(duì)于拋出異常這種情況旨椒,只要在你處理消費(fèi)邏輯的地方拋出了異常,那么 broker 也重新投遞這條消息晓褪。注意一點(diǎn),如果是被捕獲的異常综慎,則不會(huì)進(jìn)行消息重試涣仿。
消息重試,保證了消費(fèi)消息的容錯(cuò)性示惊,即使消費(fèi)失敗好港,也不需要開發(fā)者自己去編寫代碼來做補(bǔ)償,大大提高了開發(fā)效率米罚,同時(shí)也是 RocketMQ 相較于其他 MQ 的一個(gè)非常好的特性钧汹。
消息冪等
首先什么是消費(fèi)冪等呢?簡(jiǎn)單來說就是對(duì)于一條消息的處理結(jié)果录择,不管這條消息被處理多少次拔莱,最終的結(jié)果都一樣。比如說隘竭,你收到一條消息是要更新一個(gè)商品的價(jià)格為 6.8 元辨宠,那么當(dāng)這條消息執(zhí)行 1 次,還是執(zhí)行 100 次货裹,最終在數(shù)據(jù)庫(kù)里的該商品價(jià)格就是 6.8 元嗤形,這就是所謂的冪等。 那么為什么消費(fèi)需要冪等呢弧圆?因?yàn)樵趯?shí)際使用中赋兵,尤其在網(wǎng)絡(luò)不穩(wěn)定的情況下,RocketMQ 的消息有可能會(huì)出現(xiàn)重復(fù)搔预,包括兩種情況:
- 發(fā)送時(shí)消息重復(fù)霹期;
- 投遞時(shí)消息重復(fù);
第一種情況是生產(chǎn)者發(fā)送消息的場(chǎng)景拯田,消息已成功發(fā)送到 broker 历造,但是此時(shí)可能發(fā)生網(wǎng)絡(luò)閃斷或者生產(chǎn)者宕機(jī)了,導(dǎo)致 broker 發(fā)回的響應(yīng)失敗船庇。這時(shí)候生產(chǎn)者由于沒有收到響應(yīng)吭产,認(rèn)為消息發(fā)送失敗,于是嘗試再次發(fā)送消息給 broker鸭轮。這樣一來臣淤,broker 就會(huì)再收到一條一摸一樣內(nèi)容的消息,最終造成了消費(fèi)者也收到兩條內(nèi)容一摸一樣的消息窃爷。
第二種情況是消費(fèi)者消費(fèi)消息的場(chǎng)景邑蒋,消息已投遞到消費(fèi)者并完成消費(fèi)邏輯處理姓蜂,當(dāng)消費(fèi)者給 broker 反饋消費(fèi)狀態(tài)時(shí)可能發(fā)生網(wǎng)絡(luò)閃斷。broker 收不到消費(fèi)者的消費(fèi)狀態(tài)医吊,為了保證至少消費(fèi)一次的語(yǔ)義钱慢,broker 將在網(wǎng)絡(luò)恢復(fù)后再次嘗試投遞之前已經(jīng)被處理過的消息,最終造成消費(fèi)者收到兩條內(nèi)容一摸一樣的消息卿堂。
當(dāng)然對(duì)于一些允許消息重復(fù)的場(chǎng)景滩字,大可以不必關(guān)心消費(fèi)冪等。但是對(duì)于那些不允許消息重復(fù)的業(yè)務(wù)場(chǎng)景來說御吞,處理建議就是通過業(yè)務(wù)上的唯一標(biāo)識(shí)來作為冪等處理的依據(jù)麦箍。
消費(fèi)冪等主要是針對(duì)那些不允許消息重復(fù)的場(chǎng)景,應(yīng)該說大部分 MQ 都需要冪等處理陶珠,這屬于代碼邏輯或者說業(yè)務(wù)上的需要挟裂,最好的處理方式就是前面所說的根據(jù)業(yè)務(wù)上唯一標(biāo)識(shí)來作為冪等處理的依據(jù)。