一、RabbitMQ的優(yōu)點(diǎn)
1、應(yīng)用解耦
提高系統(tǒng)容錯性和可維護(hù)性
在訂單系統(tǒng)中,可以通過遠(yuǎn)程調(diào)用直接調(diào)用庫存系統(tǒng),支付系統(tǒng),物流系統(tǒng)。
但是這三個系統(tǒng)耦合度太高了,因為訂單系統(tǒng)下完訂單首先去庫存系統(tǒng)將庫存-1,然后將返回值返回給訂單系統(tǒng),然后通過訂單系統(tǒng)的返回結(jié)果來在支付系統(tǒng)進(jìn)行支付,當(dāng)支付完成后將返回結(jié)果返回給訂單系統(tǒng),最后物流系統(tǒng)拿著支付系統(tǒng)的返回結(jié)果進(jìn)行物流發(fā)貨。
第一種情況是當(dāng)庫存系統(tǒng)因為網(wǎng)絡(luò)波動無法收到訂單系統(tǒng)的消息或者受到時間過長會導(dǎo)致整個鏈路的崩潰
第二種情況是新增一個與訂單系統(tǒng)相關(guān)聯(lián)的X系統(tǒng),就需要在訂單系統(tǒng)的源碼種進(jìn)行改寫,這樣會造成高內(nèi)聚對后續(xù)應(yīng)用的維護(hù)成本較高
對于以上的情況可以使用MQ來解決,使其應(yīng)用解耦。
對于情況一:假如此刻庫存系統(tǒng)出問題,好幾分鐘才恢復(fù)好,但是對訂單系統(tǒng)沒有任何影響,只需要重新從MQ中獲取消息即可。
?
對于情況二:當(dāng)新增一個X系統(tǒng),只需要創(chuàng)建獨(dú)立的X系統(tǒng)模塊,然后X系統(tǒng)從MQ中獲取消息,不再需要在訂單系統(tǒng)源碼中添加功能,這樣做到了解耦,提高了維護(hù)性和容錯性。
2、異步提速
提升用戶體驗和系統(tǒng)吞吐量
當(dāng)用戶下完單以后,訂單系統(tǒng)需要在數(shù)據(jù)庫中保存訂單信息到訂單表花費(fèi)20ms,然后訂單系統(tǒng)首先在庫存系統(tǒng)操作并返回結(jié)果到訂單系統(tǒng)花費(fèi)300ms,支付系統(tǒng)和物流系統(tǒng)同意也各自花費(fèi)300ms。這樣就花費(fèi)300+300+300+20=920ms后訂單系統(tǒng)才能將結(jié)果返回給用戶,延時太長?
對于這種情況,可以使用MQ來處理,用戶下完單就向數(shù)據(jù)庫下單保存訂單信息到訂單表花費(fèi)20ms,然后花費(fèi)ms向MQ發(fā)送訂單消息,最后MQ分別花費(fèi)3×5=15ms向庫存系統(tǒng)、支付系統(tǒng)、物流系統(tǒng)發(fā)送消息?。至于這三個系統(tǒng)收到消息處理的時間多少,就與訂單系統(tǒng)不再有關(guān)系。用戶一共消費(fèi)5+20=25ms就可以收到下單成功響應(yīng)。
3、削峰填谷
提高系統(tǒng)穩(wěn)定性
對于秒殺活動,很多用戶會在同一時間瘋狂的下單,這樣導(dǎo)致大量的請求讓系統(tǒng)無法響應(yīng)導(dǎo)致宕機(jī)。?
對于以上的情況可以使用MQ來解決,用戶的大量請求不再直接與系統(tǒng)對接,而是與MQ對接。然后大量消息進(jìn)入隊列。
然后系統(tǒng)每秒從MQ中拉取自己所稱承受的最大請求,這樣就可以解決這種問題,可以提高系統(tǒng)的穩(wěn)定性。
使用了MQ之后,限制消費(fèi)消息的速度為1000,這樣一來,高峰期產(chǎn)生的數(shù)據(jù)勢必會被積壓在 MQ 中,高峰就被“削”掉了,但是因為消息積壓,在高峰期過后的一段時間內(nèi),消費(fèi)消息的速度還是會維持在1000,直到消費(fèi)完積壓的消息,這就叫做“填谷”
二、RabbitMQ的缺點(diǎn)
1、系統(tǒng)可用性降低
系統(tǒng)引入的外部依賴越多,系統(tǒng)穩(wěn)定性越差。一旦 MQ 宕機(jī),就會對業(yè)務(wù)造成影響。如何保證MQ的高可用?
2、系統(tǒng)復(fù)雜度提高
MQ 的加入大大增加了系統(tǒng)的復(fù)雜度,以前系統(tǒng)間是同步的遠(yuǎn)程調(diào)用,現(xiàn)在是通過 MQ 進(jìn)行異步調(diào)用。如何保證消息沒有被重復(fù)消費(fèi)?怎么處理消息丟失情況?那么保證消息傳遞的順序性?
3、?一致性問題
A系統(tǒng)處理完業(yè)務(wù)通過MQ給B、C、D三個系統(tǒng)發(fā)消息數(shù)據(jù),如果B 系統(tǒng)、C系統(tǒng)處理成功,D 系統(tǒng)外理失敗。如何保證消息數(shù)據(jù)處理的一致性?
三、RabbitMQ的五種隊列形式
1、點(diǎn)對點(diǎn)隊列
功能?:一個生產(chǎn)者投遞消息給隊列,只能允許有一個消費(fèi)者進(jìn)行消費(fèi)。
?推拉模式:?
- 推:消費(fèi)者已經(jīng)啟動了,建立長連接,一旦生產(chǎn)者向隊列投遞消息會馬上推送給消費(fèi)者。
- 拉:生產(chǎn)者先投遞消息到隊列進(jìn)行緩存,這時候消費(fèi)者再啟動的時候就會向隊列獲取消息。
?應(yīng)答模式:?
- 自動應(yīng)答:不在乎消費(fèi)者對這個消息處理是否成功,都會告訴隊列刪除消息,如果處理消息失敗的情況下,實(shí)現(xiàn)自動補(bǔ)償。
- 手動應(yīng)答:消費(fèi)處理完業(yè)務(wù)邏輯,手動返回ACK(通知)告知對隊列服務(wù)器是否刪除該消息。
為了確保消息不會丟失,RabbitMQ支持消息應(yīng)答。消費(fèi)者發(fā)送一個消息應(yīng)答,告訴RabbitMQ這個消息已經(jīng)接收并且處理完畢了。RabbitMQ就可以刪除它了
如果一個消費(fèi)者掛掉卻沒有發(fā)送應(yīng)答,RabbitMQ會理解為這個消息沒有處理完全,然后交給另一個消費(fèi)者去重新處理。這樣,你就可以確認(rèn)即使消費(fèi)者偶爾掛掉也不會丟失任何消息了。
沒有任何消息超時限制;只有當(dāng)消費(fèi)者掛掉時,RabbitMQ才會重新投遞。即使處理一條消息會花費(fèi)很長的時間。
消息應(yīng)答是默認(rèn)打開的。我們通過顯示的設(shè)置??autoAsk=true??關(guān)閉這種機(jī)制。現(xiàn)即自動應(yīng)答開,一旦我們完成任務(wù),消費(fèi)者會自動發(fā)送應(yīng)答。通知RabbitMQ消息已被處理,可以從內(nèi)存刪除。如果消費(fèi)者因宕機(jī)或鏈接失敗等原因沒有發(fā)送ACK(不同于ActiveMQ,在RabbitMQ里,消息沒有過期的概念),則RabbitMQ會將消息重新發(fā)送給其他監(jiān)聽在隊列的下一個消費(fèi)者
2、工作隊列模式
?功能?:隊列服務(wù)器向消費(fèi)者發(fā)送消息的時候,消費(fèi)者采用手動應(yīng)答模式,隊列服務(wù)器必須要接到消費(fèi)者發(fā)送ack結(jié)果通知,才會繼續(xù)發(fā)送下一個消息。工作隊列稱為“能者多勞隊列”,誰應(yīng)答的快,誰就能多消費(fèi)信息。
?工作模式(默認(rèn)消費(fèi)者集群均攤消費(fèi))?:
- 假設(shè)生產(chǎn)者向隊列發(fā)送10個消息,消費(fèi)者1和消費(fèi)者2都各自消費(fèi)5個,保證了消費(fèi)的唯一性。
?弊端?:
- 均攤消費(fèi)會帶來一些弊端:如果每個消費(fèi)者處理消費(fèi)的業(yè)務(wù)時間不相同的情況,可能對消費(fèi)者處理比較慢的服務(wù)器不公平
?RabbitMQ的公平轉(zhuǎn)發(fā):
目前消息轉(zhuǎn)發(fā)機(jī)制是平均分配,這樣就會出現(xiàn)倆個消費(fèi)者,奇數(shù)的任務(wù)很耗時,偶數(shù)的任何工作量很小,造成的原因就是近當(dāng)消息到達(dá)隊列進(jìn)行轉(zhuǎn)發(fā)消息。并不在乎有多少任務(wù)消費(fèi)者并未傳遞一個應(yīng)答給RabbitMQ。僅僅盲目轉(zhuǎn)發(fā)所有的奇數(shù)給一個消費(fèi)者,偶數(shù)給另一個消費(fèi)者。
為了解決這樣的問題,我們可以使用basicQos方法,傳遞參數(shù)為??prefetchCount= 1??,這樣告訴RabbitMQ不要在同一時間給一個消費(fèi)者超過一條消息。
換句話說,只有在消費(fèi)者空閑的時候會發(fā)送下一條信息。調(diào)度分發(fā)消息的方式,也就是告訴RabbitMQ每次只給消費(fèi)者處理一條消息,也就是等待消費(fèi)者處理完畢并自己對剛剛處理的消息進(jìn)行確認(rèn)之后,才發(fā)送下一條消息,防止消費(fèi)者太過于忙碌,也防止它太過去清閑。(??通過設(shè)置channel.basicQos(1);??)
3、發(fā)布訂閱模式
?功能?:一個生產(chǎn)者發(fā)送消息,多個消費(fèi)者獲同樣的消息(包括一個生產(chǎn)者、一個交換機(jī)、多個隊列、多個消費(fèi)者)。
「點(diǎn)對點(diǎn)」和「工作隊列模式」都是消息只能發(fā)送到指定的queue中,但是想要類似廣播的效果,發(fā)給所有消費(fèi)者,這時候就需要用到交換機(jī)(exchange)了。?
注意:交換機(jī)沒有存儲消息功能,如果消息發(fā)送到?jīng)]有綁定消費(fèi)隊列的交換機(jī),消息則丟失。
4、路由模式Routing
功能:? 生產(chǎn)者發(fā)送消息到交換機(jī)并指定一個路由key,消息隊列綁定到交換機(jī)時要指定路由key(key匹配就能接收消息,key不匹配就不能接收消息)。
這其實(shí)就是Direct組播模式,設(shè)置好Exchange交換機(jī)的類型,轉(zhuǎn)發(fā)的時候,會檢查隊列中的RoutingKey值,如果和消息的關(guān)鍵字相同則轉(zhuǎn)發(fā),否則丟棄。
5、通配符模式Topics
?功能:? 此模式是在路由模式的基礎(chǔ)上,使用了通配符來管理消費(fèi)者接收消息。生產(chǎn)者發(fā)送消息到交換機(jī),交換機(jī)根據(jù)綁定隊列的RoutingKey的值??進(jìn)行通配符匹配??;
通配符模式,其實(shí)和路由模式相類似,但是這個支持模糊匹配。
例如:
- ?符號#?:匹配一個或者多個詞lazy.# 可以匹配lazy.irs或者lazy.irs.cor
- ?符號?*:只能匹配一個詞lazy.* 可以匹配lazy.irs或者lazy.cor
四、RabbitMQ高級特性
1、消息的可靠投遞
在使用 RabbitMQ的時候,作為消息發(fā)送方希望杜絕任何消息丟失或者投遞失敗場景。RabbitMQ為我們提供了兩種方式用來控制消息的投遞可靠性模式。
- confirm確認(rèn)模式
- return退回模式
?rabbitmq整個消息投遞的路徑為:producer--->exchange--->queue--->consumer
- confirm確認(rèn)模式:消息從producer到exchange 則會返回一個confirmCallback。交換機(jī)接收消息如果成功了返回成功的消息,如果失敗了返回失敗的消息。
- return退回模式:消息從exchange-->queue 投遞失敗則會返回一個 returnCallback。當(dāng)消息發(fā)送給交換機(jī),交換機(jī)路由到隊列失敗了只返回失敗的消息,成功的消息不返回。
2、Consumer ACK
ack指Acknowledge,確認(rèn)。 表示消費(fèi)端收到消息后的確認(rèn)方式。
有三種確認(rèn)方式:
- 自動確認(rèn):acknowledge=“none” 默認(rèn)方式
- 手動確認(rèn):acknowledge=“manual”
- 根據(jù)異常情況確認(rèn):acknowledge=“auto”,(這種方式使用麻煩)
????????其中自動確認(rèn)是指,當(dāng)消息一旦被Consumer接收到,則自動確認(rèn)收到,并將相應(yīng) message 從 RabbitMQ 的消息緩存中移除。
? ? ? ? 但是在實(shí)際業(yè)務(wù)處理中,很可能消息接收到,業(yè)務(wù)處理出現(xiàn)異常,那么該消息就會丟失。如果設(shè)置了手動確認(rèn)方式,則需要在業(yè)務(wù)處理成功后,調(diào)用channel.basicAck(),手動簽收,如果出現(xiàn)異常,則調(diào)用channel.basicNack()方法,讓其自動重新發(fā)送消息。
3、消費(fèi)端限流
如上圖場景,A系統(tǒng)最大處理請求位1000個,當(dāng)A系統(tǒng)維護(hù)的時候,MQ以及堆積了很多消息。此刻A系統(tǒng)已經(jīng)維護(hù)好了,如果MQ消息全部大量涌向A系統(tǒng)就會造成A系統(tǒng)宕機(jī),所以需要進(jìn)行消費(fèi)的限流,將MQ的消息發(fā)送數(shù)量進(jìn)行限制,讓A系統(tǒng)所能消化的最大請求量。
- 配置 prefetch屬性設(shè)置消費(fèi)端一次拉取多少消息(spring 設(shè)置) springboot在yml文件中設(shè)置
- 消費(fèi)端的確認(rèn)模式一定為手動確認(rèn)。acknowledge=“manual”,只有手動簽收之后才會拉去下一條消息
spring:
rabbitmq:
listener:
simple:
prefetch: 1 # 一次拉去多少消息
acknowledge-mode: manual # 設(shè)置確認(rèn)模式
這樣就可以限制消費(fèi)者每次對消息拉取的次數(shù),防止大量消息涌入導(dǎo)致宕機(jī)?
4、TTL存活時間
- TTL 全稱 Time To Live(存活時間/過期時間)。
- 當(dāng)消息到達(dá)存活時間后,還沒有被消費(fèi),會被自動清除。
- RabbitMQ可以對消息設(shè)置過期時間,也可以對整個隊列(Queue)設(shè)置過期時間。
過期時間策略有兩種:
- 會對整個隊列消息統(tǒng)一過期。
- 當(dāng)該消息在隊列頭部時(消費(fèi)時)會單獨(dú)判斷這一消息是否過期。
5、死信隊列?
死信隊列,英文縮寫:DLX 。Dead Letter Exchange(死信交換機(jī)),當(dāng)消息成為Dead message后,可以被重新發(fā)送到另一個交換機(jī),這個交換機(jī)就是DLX。
消息成為死信的三種情況:
- 消息被拒絕
- 消息TTL過期
- 隊列達(dá)到最大長度
6、延遲隊列?
延遲隊列,即消息進(jìn)入隊列后不會立即被消費(fèi),只有到達(dá)指定時間后,才會被消費(fèi)。
- 但在RabbitMQ中并未提供延遲隊列功能。
- 可以使用: TTL+死信隊列 組合實(shí)現(xiàn)延遲隊列的效果
需求:
- 淘寶七天自動確認(rèn)收貨。在我們簽收商品后,物流系統(tǒng)會在七天后延時發(fā)送一個消息給支付系統(tǒng),通知支付系統(tǒng)將貨款打給商家,這個過程持續(xù)七天,就是使用了MQ的延遲推送功能;
- 訂單在十分鐘之內(nèi)未支付則自動取消;
- 新創(chuàng)建的店鋪,如果在十天內(nèi)都沒有上傳過商品,則自動發(fā)送消息提醒;
- 用戶注冊成功后,如果三天內(nèi)沒有登陸則進(jìn)行短信提醒;
- 用戶發(fā)起退款,如果三天內(nèi)沒有得到處理則通知相關(guān)運(yùn)營人員;
- 預(yù)定會議后,需要在預(yù)定的時間點(diǎn)前十分鐘通知各個與會人員參加會議。
?
如上圖,實(shí)現(xiàn)一個下單30分鐘后未支付,取消訂單并且回滾庫存這個功能就可以使用延遲隊列。
當(dāng)訂單系統(tǒng)下單后,發(fā)送一條消息給MQ,然后MQ收到消息設(shè)置30分鐘后消費(fèi)消息。當(dāng)?shù)?0分鐘時候,將這條消息發(fā)送給庫存系統(tǒng),判斷訂單是否支付,如果支付了就不做什么,如果未支付,那么就取消訂單,回滾庫存。
當(dāng)然定時任務(wù)也可以勉強(qiáng)實(shí)現(xiàn)這個功能,不過定時任務(wù)時間設(shè)置不能完美的達(dá)到要求,如果時間設(shè)置過長,比如1分鐘判斷一次,那么就會造成29分鐘或者31分鐘進(jìn)行判斷。如果1秒判斷一次會造成頻繁的查詢數(shù)據(jù)庫導(dǎo)致數(shù)據(jù)庫訪問壓力過大。
不過RabbitMQ沒有延遲隊列功能,不過可以使用TTL+死信隊列完成延遲隊列。文章來源:http://www.zghlxwxcb.cn/news/detail-720477.html
如上圖,當(dāng)訂單系統(tǒng)下完訂單發(fā)送消息給隊列,這條消息的TTL時間設(shè)置為30分鐘。當(dāng)30分鐘后該消息過期了進(jìn)入死信交換機(jī),死信交換機(jī)將該過期消息發(fā)送給私信隊列,最后死信隊列將過期消息發(fā)送給庫存系統(tǒng)提醒庫存系統(tǒng)進(jìn)行判斷該訂單是否支付。?文章來源地址http://www.zghlxwxcb.cn/news/detail-720477.html
到了這里,關(guān)于RabbitMQ的高級特性及其特點(diǎn)的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!