MQ的消息模型及在工作上應用場景
MQ介紹
根據(jù)某科的介紹,MQ(message queue),叫消息隊列,是基礎數(shù)據(jù)結構中先進先出的一種數(shù)據(jù)機構。
一般用來解決應用解耦,異步消息,流量削鋒等問題,實現(xiàn)高性能,高可用,可伸縮和最終一致性架構。
| 名詞 | 解釋 |
|---|---|
| 解耦 | 簡單說就是積木化,每個東西都相互獨立,比如漢堡包,面包跟肉餅是相互獨立,可以單獨使用,也可以組合成一個食物 |
| 異步 | 去買漢堡包,下單之后就去玩手機,等服務員叫號通知領取,這就叫異步;而同步是下單后,什么都不能干,直到服務員叫號才能做其他事 |
| 限流 | 大家 9 點上班,地鐵進不去,門口做限流 |
| 削峰 | 遵從最后落地到數(shù)據(jù)庫的請求數(shù)要盡量少的原則,比如讓 1/2 的人下午開始上班、局部停電,感興趣可以查看削峰填谷 |
| 消息 | 要傳輸?shù)膬热荩热缯f話、寫信,形式不重要,按照雙方約定的格式即可 |
| 隊列 | 是一種先進先出的數(shù)據(jù)結構,排隊打疫苗,從隊尾入隊,從隊頭出隊 |
MQ 主要產(chǎn)品包括:RabbitMQ、ActiveMQ、RocketMQ、ZeroMQ、Kafka
通過上述的內容,不難發(fā)現(xiàn),MQ是一種跨進程的通信機制,用于上下游傳遞消息,而個人覺得MQ有點像中介, 房東發(fā)布出租信息,信息放在中介處,租客來通過中介來租房子。
使用 MQ 的好處
舉個通俗點的例子:
面試官希望 HR 早點招聘到合適的人選,于是一開始是這樣的:
HR 問面試官什么時候有空,把候選人資料送過去,并且親自看到面試官看完并給出結論后才離開,時間一長,大家都覺得很麻煩,HR 覺得候選人不錯,面試官覺得不合適,容易發(fā)生爭執(zhí)。
后面,HR 跟面試官說,我把資料放在桌子上,你有空記得看,然后每次面試官看到桌子有資料后,都會拿起來看。
在這個場景上,HR就是生產(chǎn)者,面試官就是消費者,桌子就是MQ。
使用MQ帶來的好處是解決應用解耦,異步消息,流量削鋒:
- HR想給資料時,無需知道面試官是否有空,只需要把資料放桌子上即可,這樣大家都有時間做別的事,節(jié)省大家的時間。。應用解耦,每個成員都是獨立的,不受其他成員影響。面試官不關心誰放的資料,HR 不關心誰哪個面試官看的資料
- 如果別的組也有招聘需求(且當是同一工種,比如 Java 后端開發(fā)),HR依然把資料放在桌子上,兩個面試官只需要各自從桌子上取資料查閱即可。異步消息,HR 把資料放在桌子上即可,就可以去做別的事,比一開始親自看著的效率高太多了
- HR無需關注面試官什么時候查看資料,也不關注看資料用多長的時間,減少矛盾。流量削峰,HR 給資料的頻率不固定,面試官看資料的時長也不固定,面試官只需要在固定時間內看完給結論即可,不會有那么大的壓力。
使用 MQ 的壞處
| 名詞 | 解釋 |
|---|---|
| 引入復雜度 | 「桌子」這東西是使用 MQ 后多出來的,需要有地方放桌子,而且流程會變長,更復雜 |
| 不一致性 | HR會以為面試官應該看了資料,但實際面試官可能還沒開始看,這就導致了不一致性的問題,但在約束好的時間內,面試官最終的查閱狀態(tài)與HR的認知必須是要一致的,這就是所謂的最終不一致性 |
| 系統(tǒng)可用性降低 | 如果桌子壞了,后面的流程是不是就中斷了 |
當然,使用MQ還有很多問題要解決,比如資料無辜丟了、一樣的資料,給了好多份、資料被搶、本來資料給面試官 A,結果給到面試官 B等場景都是需要處理的。
什么時候用 MQ
| 名詞 | 解釋 |
|---|---|
| 生產(chǎn)者不需要從消費者處獲得反饋 | 面試官到底看了沒有,HR 根本不需關注,默認面試官是看了,否則就只能采取監(jiān)督看完的方式 |
| 容許不一致性 | HR 可能會發(fā)現(xiàn)有時候面試官說看了資料,但實際沒看的情況,只有 HR 愿意相信面試官最后看了即可 |
| 有效 | 解耦、提速等帶來的收益大于放置書桌是有成本的,那說明是有效的。比如一個月甚至半年才有一份簡歷,那還不如直接當面給更高效 |
消息模型
什么是 JMS
Java 消息服務指的是兩個應用程序之間進行異步通信的 API,它為標準消息協(xié)議和消息服務提供了一組通用接口,包括創(chuàng)建、發(fā)送、讀取消息等,用于支持 JAVA 應用程序開發(fā)。
為什么需要 JMS
在JAVA中,如果兩個應用程序之間對各自都不了解,甚至這兩個程序可能部署在不同地方上,那么它們之間如何發(fā)送消息呢?
舉個例子,一個應用程序 A 部署在印度,另一個應用程序部署在美國,然后每當 A 觸發(fā)某件事后,B 想從 A 獲取一些更新信息。
當然,也有可能不止一個 B 對 A 的更新信息感興趣,可能會有 N 個類似 B 的應用程序想從 A 中獲取更新的信息。
在這種情況下,JAVA提供了最佳的解決方案-JMS,完美解決了上面討論的問題。
點對點模型
在該模型中,有下列概念:
消息隊列 (Queue)、發(fā)送者 (Sender)、接收者 (Receiver)
每個消息都被發(fā)送到一個特定的隊列,接收者從隊列中獲取消息。隊列保留著消息,直到它們被消費或超時。
- 支持存在多個消費者
- 每個消息只有一個消費者(一旦消息被消費,消息就不再在消息隊列中)
- 發(fā)送者和接收者之間在時間上沒有依賴性,也就是說當發(fā)送者發(fā)送了消息之后,不管接收者有沒有正在運行,它不會影響到消息被發(fā)送到隊列
- 接收者在成功接收消息之后需向隊列應答成功
如果希望發(fā)送的每個消息都應該被成功處理的話,那么就需要點對點模型。
女神想找備胎 A 聊天,就單聊備 A,這就是點對點,只有一個人能收到消息

發(fā)布訂閱模型
消息生產(chǎn)者(發(fā)布)將消息發(fā)布到topic中,同時有多個消息消費者(訂閱)消費該消息。和點對點方式不同,發(fā)布到 topic 的消息會被所有訂閱者消費。。
在該模型中,有下列概念:
主題(Topic)、發(fā)布者(Publisher)、訂閱者(Subscriber)
客戶端將消息發(fā)送到主題。多個發(fā)布者將消息發(fā)送到 Topic,系統(tǒng)將這些消息傳遞給多個訂閱者。
- 每個消息可以有多個消費者
- 發(fā)布者和訂閱者有時間依賴性,只有當客戶端創(chuàng)建訂閱后才能接受消息,且訂閱者需一直保持活動狀態(tài)以接收消息
- 訂閱者創(chuàng)建一個可持久化的訂閱。這樣,即使訂閱者沒有被激活(運行),它也能接收到發(fā)布者的消息。
如果希望發(fā)送的消息可以不被做任何處理、或者被一個消費者處理、或者可以被多個消費者處理的話,那么可以采用 Pub/Sub 模型。。
女神發(fā)了個朋友圈,她的備胎們都能看到,這就是發(fā)布/訂閱。

兩個模型之間的區(qū)別
點對點模型下,不可重復消費。
點對點下,一個隊列可以有多個消費者,生產(chǎn)者發(fā)送一條消息到隊列,消費者能用隊列取出并且消費消息,一旦消息被消費后,隊列不再有存儲,所以其他消費者不能消費到已經(jīng)被消費的消息,如果一直沒有消費者處理,這條消息就會被保存,直到有可用的消費者為止。
發(fā)布訂閱模型,可以重復消費。
發(fā)布訂閱下,發(fā)布者發(fā)送到 topic 的消息,只有訂閱了 topic 的訂閱者才會收到消息,注意是所有訂閱這個 topic 的服務都能收到,所以能達到消息拷貝的效果
MQ 的在工作上應用場景
雖然上面以一個招聘的例子來講解 MQ 的應用場景,但可能還是會有疑問,不知道工作上是如何的,因此再講講工作上的場景。
異步
之前負責的一個需求叫老帶新,大致流程如下:
1)用戶下單后,會先判斷下單者身份
2)如果是新用戶,再判斷是否有邀請人
3)如果有,再判斷邀請人身份
4)如果是老用戶,就給雙方發(fā)積分

這樣的話,用戶的流程就會發(fā)生變化:

很明顯,這樣做的問題是:新增的邏輯存在堵塞下單主流程的風險。
既然同步處理會有問題,那就改異步吧,改完變成這樣:

異步的好處是,即使老帶新邏輯有問題,也不會堵塞下單流程。
這樣的好日子沒過幾天,問題又來了:老帶新業(yè)務頻繁改動,導致下單系統(tǒng)頻繁發(fā)版本,存在質量隱患。
使用 MQ
由于依賴訂單系統(tǒng)的業(yè)務越來越多,為了保證下單系統(tǒng)的穩(wěn)定性,業(yè)務層面必須解耦,只需要把支付成功的消息告訴別的業(yè)務,他們收到了通知后自行處理,我們只管自己的流程,后續(xù)還有其他業(yè)務系統(tǒng),直接訂閱我們發(fā)送的支付成功消息。

「MQ 帶來的問題」
- 如何保證消息隊列的高可用?
- 如何保證消息不被重復消費?
- 如何處理消息丟失的問題?
- 如何保證消息的順序性?
- 如何處理消息隊列大量消息積壓?
上面這些問題,都是實際工作上會遇到的,往往也都是測試點,下面也會有提及到,簡單了解下即可。
「MQ 產(chǎn)品的對比」
| 產(chǎn)品 | 單機吞吐量 | 時效性 | 可用性 | 消息可靠性 | 功能支持 |
|---|---|---|---|---|---|
| ActiveMQ | 萬級 | 毫秒級 | 高 | 較低概率出現(xiàn)丟失數(shù)據(jù) | 極其完備 |
| RabbitMQ | 萬級 | 微妙級 | 高 | 基本不丟 | erlang 開發(fā) |
| RocketMQ | 十萬級 | 毫秒級 | 非常高 | 可配置 0 丟失 | 分布式 |
| Kafka | 十萬級 | 毫秒級 | 非常高高 | 可配置 0 丟失 | 分布式 |
而在選擇上,一般公司都是用Kafka跟RocketMQ較多。
「MQ 的測試點」
生產(chǎn)者
- 生成的數(shù)據(jù)格式是否跟定義的一致
- 數(shù)據(jù)是否有成功推送到隊列里
- 數(shù)據(jù)是否有成功推動到對應的 topic
- 推送失敗時如何處理
- 重復推送同一條數(shù)據(jù),如何處理
- 不同順序推送消息,注意隊列優(yōu)先級
- 推消息耗時
- 隊列容量達到上限,無法推送后如何處理
消費者
- 消費的消息是否來自訂閱的 topic
- 消息被消費了,是否有清除
- 生產(chǎn)者推送過快,消費速度過慢(堵塞),會如何
- 無法消費沒訂閱的 topic 消息
- 生產(chǎn)者推送消息后,消費者接受到的消息內容跟生產(chǎn)者推的一致
- 如何處理重復消息,比如冪等
- 處理超時
- 消息處理失敗
- 消費消息的優(yōu)先級是否跟推的一致
- 消費消息耗時
- 消費者宕機,消息堆積,無人處理,會如何處理
- 是否能正常消費消息
隊列
- 宕機恢復后,消息是否丟失
- 宕機預案,多久能恢復,如果無法恢復的預案
- 不同的消息格式,是否能正常識別及轉發(fā)
小結
來來去去,花了一周的時間來整理這堆信息,之前有測過mq,但沒有太了解這玩意,從介紹、選型、測試點,加深了對 mq 的印象,但由于沒做過 mq 的性能測試跟自動化測試,所以這塊暫時沒有心得能輸出,如果后續(xù)有類似的經(jīng)歷,也會分享下。
本文留下了一個懸念,針對消息不一致的問題,大家是怎么解決的,這邊非常好奇,所以下篇計劃會寫分布式事務,想深入了解下細節(jié)~更多關于MQ工作場景消息模型的資料請關注腳本之家其它相關文章!
相關文章
Spring Boot集成Quartz注入Spring管理的類的方法
本篇文章主要介紹了Spring Boot集成Quartz注入Spring管理的類的方法,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2018-04-04
Java中的ArrayList.trimToSize()方法詳解
這篇文章主要介紹了Java中的ArrayList.trimToSize()方法詳解,前幾天看了Java?ArrayList,沒有明白trimToSize()這個方法是什么意思,所以看了一下源碼并且debug一下自己的一個例子,明白了其中的含義,需要的朋友可以參考下2023-11-11

