消息隊列(MQ)是一種不同應(yīng)用程序之間(跨進程)的通信方法。應(yīng)用程序通過寫入和檢索出入列隊的數(shù)據(jù)(消息)來通信绪穆,而無需通過專用連接來鏈接它們陆馁。消息傳遞指的是程序之間通過在消息中發(fā)送數(shù)據(jù)進行通信,而不是通過直接調(diào)用彼此來通信芋忿,直接調(diào)用通常是用于諸如遠程過程調(diào)用(Remote Procedure Call. RPC)的技術(shù)烫止。排隊指的是應(yīng)用程序通過隊列來通信蒋荚。隊列的使用除去了接收和發(fā)送應(yīng)用程序同時執(zhí)行的要求。這樣天然的就實現(xiàn)了異步的目標(biāo)馆蠕。那么MQ還有哪些功能場景呢期升。下面逐一介紹。
解耦
MQ最直接的使用場景就是可以將兩個系統(tǒng)進行解耦互躬,比如我們的貨款抵扣業(yè)務(wù)場景播赁,用戶生成訂單發(fā)送MQ后立即返回,結(jié)算系統(tǒng)去消費該MQ進行用戶賬戶金額的扣款吼渡。這樣訂單系統(tǒng)只需要關(guān)注把訂單創(chuàng)建成功容为,最大可能的提高訂單量,并且生成訂單后立即返回用戶寺酪。而結(jié)算系統(tǒng)重點關(guān)心的是賬戶金額的扣減坎背,保證賬戶金額最終一致。這個場景里面還會涉及到重試冪等性問題寄雀,后面有介紹得滤。
削峰填谷
還是以訂單系統(tǒng)和結(jié)算系統(tǒng)場景為例,如果訂單系統(tǒng)通過RPC框架來調(diào)用結(jié)算系統(tǒng)盒犹,在有高峰促銷的情況下生成訂單的量會非常大懂更,而且由于生成訂單的速度也非痴R担快,這樣勢必會給結(jié)算系統(tǒng)造成系統(tǒng)壓力沮协,服務(wù)器利用率則會偏高坛猪,但在不是高峰的時間點訂單量比較小,結(jié)算系統(tǒng)的服務(wù)器利用率則會偏低皂股。對于結(jié)算系統(tǒng)來說就會出現(xiàn)下面這樣的高峰波谷現(xiàn)象圖。
那么如果通過MQ的方式命黔,將訂單存儲到MQ隊列中呜呐,消費端通過拉取的方式,并且拉去速度有消費端來控制悍募,則就可以控制流量趨于平穩(wěn)蘑辑。這樣對于結(jié)算系統(tǒng)來講,就達到了削峰填谷的目的坠宴⊙蠡辏或者說起到了流控的目標(biāo)。接下來喜鼓,我們介紹一下拉取方式副砍。
拉取模式指用戶在代碼里主動調(diào)用pull方法,不需要在配置文件里面再配置<mq:listener />庄岖,拉取的速度由用戶控制豁翎,調(diào)用一次拉取一次消息進行消費,這里要重視消費的速度如果消費性能下降一定會造成積壓隅忿,因此用戶自己啟用多線程控制并行度以提高消費速度心剥。
代碼樣例:
messageConsumer.start();
for (;;){
//手動拉取消息
messageConsumer.pull(topic,messageListener);
}
method: pull(String topic,MessageListener listener)
topic:指消費的主題名
listener:是一個回調(diào)對象,當(dāng)pull拉取到消息后會主動調(diào)用listener.onMessage()背桐,
與監(jiān)聽模式的區(qū)別是:監(jiān)聽模式由MQ客戶端守護線程去不停的拉取消息進行消費优烧,拉取模式由用戶控制拉取的頻率,不主動調(diào)用就不會消費消息链峭。但是都不需要主動對消息進行確認(rèn)畦娄。這種方式更適合寫場景,保證最終結(jié)果落地即可熏版,因為讀是需要立即返回以免讓用戶長時間等待從而影響用戶體驗纷责。
最終一致性
一致性問題分為強一致性、弱一致性撼短、最終一致性再膳。大多數(shù)互聯(lián)網(wǎng)業(yè)務(wù)要求實現(xiàn)最終一致性。還是以訂單系統(tǒng)和結(jié)算系統(tǒng)業(yè)務(wù)場景舉例曲横,訂單系統(tǒng)創(chuàng)建成功一個訂單后給用戶返回的結(jié)果即是成功并明確告訴用戶會從賬戶中扣除相應(yīng)的金額喂柒。那么結(jié)算系統(tǒng)需要保持跟訂單系統(tǒng)相同的狀態(tài)即從用賬戶中實際扣除一致的金額不瓶。訂單系統(tǒng)會涉及兩個動作,一個是創(chuàng)建成功訂單灾杰,一個是發(fā)送成功通知到MQ蚊丐,我們就可以把這兩個動作放入到一個本地事務(wù)中,要么成功要么失敗艳吠。當(dāng)一次發(fā)送MQ失敗之后麦备,可以結(jié)合定時任務(wù)進行補償,這樣可以保證生成訂單的結(jié)果可以落地到mq的存儲中昭娩。同樣結(jié)算系統(tǒng)消費端依靠MQ重試機制一直發(fā)送消息凛篙,直到消費端最終確認(rèn)扣款業(yè)務(wù)成功處理完成。這樣我們通過消息落地加補償栏渺,消費端從業(yè)務(wù)上面考慮重復(fù)消費的保障呛梆,也就是做好冪等性操作,利用MQ實現(xiàn)了最終一致性磕诊。
廣播消費
MQ有兩種消息模式一種是點對點模式填物,一種是發(fā)布/訂閱模式(最常用的模式)。同時發(fā)布/訂閱模式按照消費類型又可以分為集群消費和廣播消費霎终。大部分情況下我們使用的是集群消費滞磺。
集群消費:MQ發(fā)送任何一條消息,集群中只有一臺服務(wù)器可隨機消費到這條消息神僵。如下圖:
廣播消費:MQ發(fā)送每一條消息雁刷,集群中的每一臺服務(wù)器至少消費到一次。如下圖:
廣播消費舉例:消息推送系統(tǒng)保礼。首先某一個客戶端與消息中心應(yīng)用集群中的一臺服務(wù)器建立長連接并將連接session信息保存到當(dāng)前服務(wù)器內(nèi)存中沛励,集群在消費業(yè)務(wù)消息的時候,是不知道該客戶端建立的長連接在哪一臺服務(wù)器上面炮障。這個時候通過廣播消費目派,集群中的每一臺服務(wù)器都可以消費到業(yè)務(wù)消息。在決定向用戶推送通知之前會判斷當(dāng)前服務(wù)器內(nèi)存中是否有該客戶端的連接session信息胁赢,如果有則推送企蹭,進而客戶端通過http協(xié)議拉取用戶的消息實體。如果session信息不在當(dāng)前服務(wù)器上面智末,則丟棄谅摄。如下圖:
廣播消費注意事項:
1、消費進度在消費端管理系馆,比如默認(rèn)會在主目錄下創(chuàng)建offset文件夾送漠,偏移量文件存儲在offset目錄下,出現(xiàn)重復(fù)的概率要大于集群消費由蘑。
2闽寡、MQ可以確保每條消息至少被每臺消費方服務(wù)器消費一次代兵,但是如果消費方消費失敗,不會進入重試爷狈,因此業(yè)務(wù)方需要關(guān)注消費失敗的情況植影。
3、由于廣播消費消息不會進行確認(rèn)涎永,所以管理端上顯示的積壓數(shù)會一直不變思币,需要以出對數(shù)為準(zhǔn)。
使用集群消費模擬廣播
在發(fā)布/訂閱模式中羡微,如果是集群消費支救,那么一條消息只能被集群中的隨機一臺服務(wù)器消費到,如果我們有需要集群中的每臺服務(wù)器消費到比如上面的消息推送的例子拷淘,我們使用廣播消費來實現(xiàn)。但是廣播消費有一些弊端比如不支持順序消息指孤,消費進度在客戶端維護出現(xiàn)重復(fù)的幾率要大于集群模式启涯,廣播模式下不能維護消費進度所以管理端上面的積壓數(shù)一直保持不變,我們就必須以出隊數(shù)為準(zhǔn)恃轩,也就是不能夠支持消息堆積的查詢结洼。如果要規(guī)避這些弊端,那么我們可以利用集群消費來模擬廣播叉跛,在集群消費中松忍,我們的每臺服務(wù)器上面的消費APPID是相同的,如果要達到廣播的效果筷厘,那么每臺服務(wù)器上面的消費APPID保持不同就可以了鸣峭。
重試之坑
MQ的重試功能可以保證數(shù)據(jù)結(jié)果最終得到處理,但同時也正因為有重試那么在業(yè)務(wù)處理的時候就需要格外注意冪等性的問題酥艳。比如貨款抵扣業(yè)務(wù)摊溶,訂單系統(tǒng)生成訂單之后調(diào)用結(jié)算平臺去扣除用戶的賬戶金額。結(jié)算平臺要根據(jù)流水號去計算充石,如果訂單系統(tǒng)在調(diào)用結(jié)算平臺的時候發(fā)生了網(wǎng)絡(luò)異常莫换,造成了結(jié)算平臺實際上已經(jīng)得到請求并且已處理。訂單系統(tǒng)一側(cè)認(rèn)為發(fā)生異常需要重試骤铃,后續(xù)再發(fā)送到結(jié)算平臺的訂單就會造成重復(fù)扣款問題拉岁。所以流水號尤其要注意需要保證重試過程中每次發(fā)送的流水號是一致的,結(jié)算平臺會根據(jù)流水號去做業(yè)務(wù)校驗惰爬,如果已經(jīng)處理喊暖,則丟棄,最終確保冪等性补鼻。
總結(jié)
我們介紹了MQ常見的使用場景哄啄,以及每種場景下的使用注意事項雅任。尤其是在重試功能中,重試本來是MQ提供的一種保持?jǐn)?shù)據(jù)最終可以得到確認(rèn)的方法咨跌,但是如果業(yè)務(wù)使用上面不注意冪等性沪么,則會帶來業(yè)務(wù)數(shù)據(jù)的不一致甚至像重復(fù)扣款這樣比較嚴(yán)重的后果。我們還介紹了發(fā)布/訂閱模式下的廣播消費的使用舉例锌半,也介紹了它的缺點以及可以使用集群消費來模擬廣播禽车。鑒于以上每種場景都給我們提供了很好的說明使得大家在以后使用MQ的過程中可以更好的發(fā)揮MQ的強大作用。
版權(quán)聲明 轉(zhuǎn)載請標(biāo)明作者和出處