1. 什么是消息隊列(MQ)
1.1 隊列
首先從隊列說起,隊列與棧相反题禀,隊列是先進先出,可以理解為處理的時候是從開頭開始處理膀捷。
1.2 消息
是兩個應用之間傳遞的數(shù)據(jù)迈嘹,一般是一個byte數(shù)組,byte數(shù)組里面可能會包含類似于http中的header部分和body部分耕餐。所以從這點看勒魔,消息隊列的消息和http協(xié)議還是有一些相類似的地方谎势。
1.3 消息隊列
而消息隊列,即 message queue神僵,簡稱 MQ,是在兩個應用之間傳遞消息的隊列覆劈,在消息隊列非空的情況下保礼,消息隊列中包含了一系列待處理的消息。
消息隊列提供異步通信協(xié)議责语,該協(xié)議是一種將消息放入消息隊列并且不需要立即響應來繼續(xù)處理的系統(tǒng)炮障。消息隊列將一次RPC調用分解為兩次RPC調用,消息隊列提供了一種異步通訊機制坤候,發(fā)布者將消息發(fā)送到隊列胁赢,發(fā)送成功了就行,并不關心這個消息的最終處理情況如何白筹,消息的訂閱者再從消息隊列中獲取這個消息進行處理徘键。所以整個過程中,消息的發(fā)布者并不關心時誰消費了他發(fā)的消息遍蟋,訂閱者也不關心這個消息時誰發(fā)的吹害。發(fā)布者和訂閱者只與消息隊列通訊,并不關心對方虚青,這樣可以做到發(fā)布者和訂閱者的耦合它呀。
2. 為什么使用消息隊列
在很多業(yè)務場景中,有些流程對即時性的要求是不高的棒厘。比如在電商下單后纵穿,可能會有短信通知你商品商品在打包,即將發(fā)貨奢人。顯然這種短信對我們來說沒什么重要意義谓媒。那么可以將這種對即時性要求不高的邏輯處理放入隊列。比如下單完成后發(fā)送短信功能何乎。
另外一種場景是某個操作非常的耗時句惯,比如用戶可能需要等待5秒以上才能完成土辩,因為處理時間過長,很有可能會出現(xiàn)超時的問題抢野。等待時間過長也會帶來不良的用戶體驗拷淘。所以在這種場景,可以將耗時的操作用消息隊列處理指孤。比如12306的買票功能启涯,下單后不會立刻提醒買票成功,而是會顯示處理中恃轩,大概多長時間會好结洼。用戶可以用等待的時間去做其他事情,而不是一直等待結果叉跛。時間差不多了回來刷新一下界面看看有沒有購票成功补君。
當客戶端的處理速度和服務器的處理速度相差較多時,比如客戶端處理很快昧互,不斷向服務器發(fā)送消息挽铁,服務器無法立刻處理太多請求。那么可以用消息隊列做一個“漏斗”敞掘,客戶端將消息發(fā)給消息隊列叽掘,消息存放到消息隊列之后,服務器有能力處理時再從消息隊列中拿消息出來處理玖雁,防止服務器過載更扁。
3. 常見模式
3.1 點對點模式(point to point)
如下圖:
生產(chǎn)者將消息發(fā)送到queue,消費者從queue取出消息并消費赫冬。
一個生產(chǎn)者發(fā)的消息只能被一個消費者消費浓镜,生產(chǎn)者是一點,消費者是一點劲厌,即所謂的點對點模式膛薛。另外對于queue,一旦消息被消費者消費补鼻,則會將隊列中的這條消息刪除哄啄,則下次其他消費者再獲取消息時不會再獲取到被消費的消息,防止重復消費风范。
注意從圖上可以看出咨跌,點對點模式可以有多個發(fā)布者,多個訂閱者硼婿,也不一定是Producer1的消息每次都會被Consumer1消費锌半,只要保證只被一個消費者消費即可。
3.2 發(fā)布/訂閱模式(pub/sub)
如下圖
這種是不同于“單播”的點對點格式的“廣播”方式寇漫。pub與sub即publish與subscribe刊殉。發(fā)布者發(fā)布一個消息后殉摔,可以被多個消費者消費。它們之間的對應關系是通過一個類似于廣播里的頻道的概念所關聯(lián)冗澈。只要發(fā)布者發(fā)布了某一個頻道(這里指topic)的消息钦勘,所有訂閱了該頻道的訂閱者都可以收到這個消息陋葡。所以一個消息被多個訂閱者消費亚亲。
分組訂閱
實際部署時經(jīng)常會用到訂閱組,一個組里面有多個消費者腐缤,每個消費者訂閱不同的topic捌归。然后多個組部署后,每個組都可以接受到消息岭粤,組內(nèi)再區(qū)分哪個消費者消費惜索。可以看成是一個topic下有多個Queue剃浇,每個Queue是點對點的方式巾兆,Queue之間是發(fā)布訂閱方式。如下圖所示虎囚。
4. 組成
4.1 publisher
發(fā)布者角塑,負責產(chǎn)生和發(fā)送消息到 broker
4.2 broker
消息隊列服務端,實際上消息隊列是可以沒有broker的淘讥,比如Akka(actor模型)圃伶、ZeroMQ等,其實都是基于消息的系統(tǒng)設計范式蒲列,并沒有broker窒朋。broker一般包含一個或者多個 queue。broker做的內(nèi)容包括接受publisher發(fā)來的消息蝗岖,用持久化或者非持久化的方式存儲消息侥猩,然后consumer獲得消息后如果消費成功,broker收到消費成功的消息將對應消息從隊列中刪除抵赢。如果消費失敗拭宁,則會重試n次,如果還失敗則將該消息加入死信隊列瓣俯。
4.3 consumer
消息消費者杰标,負責從 broker 中獲取消息,并進行相應處理
補充:關于消費者如何從broker中獲取消息彩匕,有兩種模式腔剂,分別叫 pull 和 push
4.3.1 消費者通過pull獲得消息
消費者覺得自己有能力消費消息時,向消息隊列發(fā)出申請驼仪,申請消息掸犬。市面上有很多經(jīng)典的也比較成熟的pull模型的消息隊列袜漩,如Kafka、MetaQ等湾碎。主動權在消費方宙攻。
4.3.1 消息隊列push消息給消費者
消息隊列通過一定的機制將消息發(fā)給他認為合適的消費者,主動者在消息隊列介褥。常見問題是如果消費者的速度比發(fā)送者的速度慢很多座掘,勢必造成消息在broker的堆積。
5. 消息隊列的優(yōu)點
1.通過異步處理提高系統(tǒng)性能(削峰柔滔、減少響應所需時間);
2.屏蔽異構平臺的細節(jié):發(fā)送方溢陪、接收方系統(tǒng)之間不需要了解雙方,只需認識消息睛廊。
3.異步:消息堆積能力形真;發(fā)送方接收方不需同時在線,發(fā)送方接收方不需同時擴容(削峰)超全。
4.解耦:防止引入過多的API給系統(tǒng)的穩(wěn)定性帶來風險咆霜;調用方使用不當會給被調用方系統(tǒng)造成壓力,被調用方處理不當會降低調用方系統(tǒng)的響應能力嘶朱。
5.復用:一次發(fā)送多次消費蛾坯。
6.可靠:一次保證消息的傳遞。如果發(fā)送消息時接收者不可用见咒,消息隊列會保留消息偿衰,直到成功地傳遞它。
7.提供路由:發(fā)送者無需與接收者建立連接改览,雙方通過消息隊列保證消息能夠從發(fā)送者路由到接收者下翎,甚至對于本來網(wǎng)絡不易互通的兩個服務,也可以提供消息路由宝当。
6. 消息隊列的缺點
- 系統(tǒng)可用性降低: 考慮消息丟失或者說消息隊列掛掉等情況视事。
- 系統(tǒng)復雜性提高: 加入消息隊列之后,需要保證消息沒有被重復消費庆揩、處理消息丟失的情況俐东、保證消息傳遞的順序性等等問題!
- 一致性問題:消息隊列帶來的異步確實可以提高系統(tǒng)響應速度订晌。但是虏辫,萬一消息的真正消費者并沒有正確消費,這樣就會導致數(shù)據(jù)不一致的情況了锈拨。需要考慮實現(xiàn)最終一致性(最終一致性指的是兩個系統(tǒng)的狀態(tài)保持一致砌庄,要么都成功,要么都失敗。)
5. 消費順序
在這點上娄昆,消息隊列的基本要求是需要保證順序是FIFO的佩微,消息不能被重復消費。
7. 常見的消息隊列
- ActiveMQ
- RabbitMQ:推薦
- RocketMQ:有可能消息重復消費萌焰,適合日志系統(tǒng)