RabbitMQ 即一個消息隊列濒生,主要是用來實現(xiàn)應(yīng)用程序的異步和解耦埋泵,同時也能起到消息緩沖,消息分發(fā)的作用罪治。
①.通過異步處理提高系統(tǒng)性能
通過異步處理提高系統(tǒng)性能
如上圖丽声,在不使用消息隊列服務(wù)器的時候,用戶的請求數(shù)據(jù)直接寫入數(shù)據(jù)庫觉义,在高并發(fā)的情況下數(shù)據(jù)庫壓力劇增雁社,使得響應(yīng)速度變慢。但是在使用消息隊列之后晒骇,用戶的請求數(shù)據(jù)發(fā)送給消息隊列之后立即 返回霉撵,再由消息隊列的消費者進(jìn)程從消息隊列中獲取數(shù)據(jù)磺浙,異步寫入數(shù)據(jù)庫。由于消息隊列服務(wù)器處理速度快于數(shù)據(jù)庫(消息隊列也比數(shù)據(jù)庫有更好的伸縮性)徒坡,因此響應(yīng)速度得到大幅改善撕氧。
通過以上分析我們可以得出消息隊列具有很好的削峰作用的功能——即通過異步處理,將短時間高并發(fā)產(chǎn)生的事務(wù)消息存儲在消息隊列中喇完,從而削平高峰期的并發(fā)事務(wù)呵曹。 舉例:在電子商務(wù)一些秒殺、促銷活動中何暮,合理使用消息隊列可以有效抵御促銷活動剛開始大量訂單涌入對系統(tǒng)的沖擊奄喂。如下圖所示:
|
合理使用消息隊列可以有效抵御促銷活動剛開始大量訂單涌入對系統(tǒng)的沖擊
因為用戶請求數(shù)據(jù)寫入消息隊列之后就立即返回給用戶了,但是請求數(shù)據(jù)在后續(xù)的業(yè)務(wù)校驗海洼、寫數(shù)據(jù)庫等操作中可能失敗跨新。因此使用消息隊列進(jìn)行異步處理之后,需要適當(dāng)修改業(yè)務(wù)流程進(jìn)行配合坏逢,比如用戶在提交訂單之后域帐,訂單數(shù)據(jù)寫入消息隊列,不能立即返回用戶訂單提交成功是整,需要在消息隊列的訂單消費者進(jìn)程真正處理完該訂單之后肖揣,甚至出庫后,再通過電子郵件或短信通知用戶訂單成功浮入,以免交易糾紛龙优。這就類似我們平時手機(jī)訂火車票和電影票。
②.降低系統(tǒng)耦合性
我們知道模塊分布式部署以后聚合方式通常有兩種:1.分布式消息隊列和2.分布式服務(wù)事秀。
先來簡單說一下分布式服務(wù):
目前使用比較多的用來構(gòu)建SOA(Service Oriented Architecture面向服務(wù)體系結(jié)構(gòu))的分布式服務(wù)框架是阿里巴巴開源的Dubbo
再來談我們的分布式消息隊列:
我們知道如果模塊之間不存在直接調(diào)用彤断,那么新增模塊或者修改模塊就對其他模塊影響較小,這樣系統(tǒng)的可擴(kuò)展性無疑更好一些易迹。
我們最常見的事件驅(qū)動架構(gòu)類似生產(chǎn)者消費者模式宰衙,在大型網(wǎng)站中通常用利用消息隊列實現(xiàn)事件驅(qū)動結(jié)構(gòu)。如下圖所示:
利用消息隊列實現(xiàn)事件驅(qū)動結(jié)構(gòu)
消息隊列使利用發(fā)布-訂閱模式工作睹欲,消息發(fā)送者(生產(chǎn)者)發(fā)布消息供炼,一個或多個消息接受者(消費者)訂閱消息。 從上圖可以看到消息發(fā)送者(生產(chǎn)者)和消息接受者(消費者)之間沒有直接耦合窘疮,消息發(fā)送者將消息發(fā)送至分布式消息隊列即結(jié)束對消息的處理袋哼,消息接受者從分布式消息隊列獲取該消息后進(jìn)行后續(xù)處理,并不需要知道該消息從何而來考余。對新增業(yè)務(wù)先嬉,只要對該類消息感興趣轧苫,即可訂閱該消息楚堤,對原有系統(tǒng)和業(yè)務(wù)沒有任何影響疫蔓,從而實現(xiàn)網(wǎng)站業(yè)務(wù)的可擴(kuò)展性設(shè)計。
消息接受者對消息進(jìn)行過濾身冬、處理衅胀、包裝后,構(gòu)造成一個新的消息類型酥筝,將消息繼續(xù)發(fā)送出去滚躯,等待其他消息接受者訂閱該消息。因此基于事件(消息對象)驅(qū)動的業(yè)務(wù)架構(gòu)可以是一系列流程嘿歌。
另外為了避免消息隊列服務(wù)器宕機(jī)造成消息丟失掸掏,會將成功發(fā)送到消息隊列的消息存儲在消息生產(chǎn)者服務(wù)器上,等消息真正被消費者服務(wù)器處理后才刪除消息宙帝。在消息隊列服務(wù)器宕機(jī)后丧凤,生產(chǎn)者服務(wù)器會選擇分布式消息隊列服務(wù)器集群中的其他服務(wù)器發(fā)布消息。
備注: 不要認(rèn)為消息隊列只能利用發(fā)布-訂閱模式工作步脓,只不過在解耦這個特定業(yè)務(wù)環(huán)境下是使用發(fā)布-訂閱模式的愿待,比如在我們的ActiveMQ消息隊列中還有點對點工作模式,具體的會在后面的文章給大家詳細(xì)介紹靴患,這一篇文章主要還是讓大家對消息隊列有一個更透徹的了解仍侥。
2 .那么使用消息隊列會帶來什么問題?考慮過這個問題嗎鸳君?·
- 系統(tǒng)可用性降低:系統(tǒng)可用性在某種程度上降低农渊,為什么這樣說呢?在加入MQ之前或颊,你不用考慮消息丟失或者說MQ掛掉等等的情況腿时,但是,引入MQ之后你就需要去考慮了饭宾!
1.RabbitMQ的高可用性 (RabbitMQ是比較有代表性的批糟,因為是基于主從做高可用性的,我們就以他為例子講解第一種MQ的高可用性怎么實現(xiàn)看铆。)
鏡像集群模式:這種模式徽鼎,才是所謂的rabbitmq的高可用模式,跟普通集群模式不一樣的是弹惦,你創(chuàng)建的queue否淤,無論元數(shù)據(jù)還是queue里的消息都會存在于多個實例上,然后每次你寫消息到queue的時候棠隐,都會自動把消息到多個實例的queue里進(jìn)行消息同步石抡。
|
- 系統(tǒng)復(fù)雜性提高: 加入MQ之后,你需要保證消息沒有被重復(fù)消費助泽、處理消息丟失的情況啰扛、保證消息傳遞的順序性等等問題嚎京!
解決重復(fù)消費問題(1.插入之前檢驗2. 基于數(shù)據(jù)庫的唯一鍵來保證重復(fù)數(shù)據(jù)不會重復(fù)插入多條)
處理消息丟失
1.如果你要確保說寫rabbitmq的消息別丟,可以開啟confirm模式隐解,在生產(chǎn)者那里設(shè)置開啟confirm模式之后鞍帝,你每次寫的消息都會分配一個唯一的id,然后如果寫入了rabbitmq中煞茫,rabbitmq會給你回傳一個ack消息帕涌,告訴你說這個消息ok了。如果rabbitmq沒能處理這個消息续徽,會回調(diào)你一個nack接口蚓曼,告訴你這個消息接收失敗,你可以重試钦扭。而且你可以結(jié)合這個機(jī)制自己在內(nèi)存里維護(hù)每個消息id的狀態(tài)辟躏,如果超過一定時間還沒接收到這個消息的回調(diào),那么你可以重發(fā)土全。
保證順序性
(1)rabbitmq:拆分多個queue捎琐,每個queue一個consumer,就是多一些queue而已裹匙,確實是麻煩點瑞凑;或者就一個queue但是對應(yīng)一個consumer,然后這個consumer內(nèi)部用內(nèi)存隊列做排隊概页,然后分發(fā)給底層不同的worker來處理
一致性問題: 我上面講了消息隊列可以實現(xiàn)異步籽御,消息隊列帶來的異步確實可以提高系統(tǒng)響應(yīng)速度。但是惰匙,萬一消息的真正消費者并沒有正確消費消息怎么辦技掏?這樣就會導(dǎo)致數(shù)據(jù)不一致的情況了!
2.RabbitMQ自帶的解決方案
RabbitMQ提供以下兩種方式解決上述問題。
2.1事務(wù)機(jī)制
- 事務(wù)機(jī)制能夠解決生產(chǎn)者與broker之間消息確認(rèn)的問題项鬼,只有消息成功被broker接受哑梳,事務(wù)才能提交成功,否則就進(jìn)行事務(wù)回滾操作并進(jìn)行消息重發(fā)绘盟。但是使用事務(wù)機(jī)制會降低RabbitMQ的消息吞吐量鸠真,不適用于需要發(fā)布大量消息的業(yè)務(wù)場景。
2.2消息確認(rèn)機(jī)制
生產(chǎn)者將信道設(shè)置成confirm模式龄毡,一旦信道進(jìn)入confirm模式吠卷,所有在該信道上面發(fā)布的消息都會被指派一個唯一的ID(從1開始),一旦消息被投遞到所有匹配的隊列之后沦零,broker就會發(fā)送一個確認(rèn)給生產(chǎn)者(包含消息的唯一ID)祭隔,這就使得生產(chǎn)者知道消息已經(jīng)正確到達(dá)目的隊列了。
與事務(wù)機(jī)制相比較路操,確認(rèn)機(jī)制采用異步回調(diào)方式來處理確認(rèn)消息疾渴,性能得到了較大的提升千贯,可以確保數(shù)據(jù)同步的一致性。
消息隊列的常見使用場景吧程奠,其實場景有很多,但是比較核心的有3個:解耦祭钉、異步瞄沙、削峰
1.解耦
1.1 解耦前
1.2 解耦后
2.異步
2.1 異步前
2.2 異步后
3.削峰
3.1 削峰前
3.2 削峰后