MQ的消息模型及在工作上應(yīng)用場景
MQ介紹
根據(jù)某科的介紹,MQ(message queue),叫消息隊列,是基礎(chǔ)數(shù)據(jù)結(jié)構(gòu)中先進先出的一種數(shù)據(jù)機構(gòu)。
一般用來解決應(yīng)用解耦,異步消息,流量削鋒等問題,實現(xiàn)高性能,高可用,可伸縮和最終一致性架構(gòu)。
名詞 | 解釋 |
---|---|
解耦 | 簡單說就是積木化,每個東西都相互獨立,比如漢堡包,面包跟肉餅是相互獨立,可以單獨使用,也可以組合成一個食物 |
異步 | 去買漢堡包,下單之后就去玩手機,等服務(wù)員叫號通知領(lǐng)取,這就叫異步;而同步是下單后,什么都不能干,直到服務(wù)員叫號才能做其他事 |
限流 | 大家 9 點上班,地鐵進不去,門口做限流 |
削峰 | 遵從最后落地到數(shù)據(jù)庫的請求數(shù)要盡量少的原則,比如讓 1/2 的人下午開始上班、局部停電,感興趣可以查看削峰填谷 |
消息 | 要傳輸?shù)膬?nèi)容,比如說話、寫信,形式不重要,按照雙方約定的格式即可 |
隊列 | 是一種先進先出的數(shù)據(jù)結(jié)構(gòu),排隊打疫苗,從隊尾入隊,從隊頭出隊 |
MQ 主要產(chǎn)品包括:RabbitMQ、ActiveMQ、RocketMQ、ZeroMQ、Kafka
通過上述的內(nèi)容,不難發(fā)現(xiàn),MQ是一種跨進程的通信機制,用于上下游傳遞消息,而個人覺得MQ有點像中介, 房東發(fā)布出租信息,信息放在中介處,租客來通過中介來租房子。
使用 MQ 的好處
舉個通俗點的例子:
面試官希望 HR 早點招聘到合適的人選,于是一開始是這樣的:
HR 問面試官什么時候有空,把候選人資料送過去,并且親自看到面試官看完并給出結(jié)論后才離開,時間一長,大家都覺得很麻煩,HR 覺得候選人不錯,面試官覺得不合適,容易發(fā)生爭執(zhí)。
后面,HR 跟面試官說,我把資料放在桌子上,你有空記得看,然后每次面試官看到桌子有資料后,都會拿起來看。
在這個場景上,HR就是生產(chǎn)者,面試官就是消費者,桌子就是MQ。
使用MQ帶來的好處是解決應(yīng)用解耦,異步消息,流量削鋒:
- HR想給資料時,無需知道面試官是否有空,只需要把資料放桌子上即可,這樣大家都有時間做別的事,節(jié)省大家的時間。。應(yīng)用解耦,每個成員都是獨立的,不受其他成員影響。面試官不關(guān)心誰放的資料,HR 不關(guān)心誰哪個面試官看的資料
- 如果別的組也有招聘需求(且當(dāng)是同一工種,比如 Java 后端開發(fā)),HR依然把資料放在桌子上,兩個面試官只需要各自從桌子上取資料查閱即可。異步消息,HR 把資料放在桌子上即可,就可以去做別的事,比一開始親自看著的效率高太多了
- HR無需關(guān)注面試官什么時候查看資料,也不關(guān)注看資料用多長的時間,減少矛盾。流量削峰,HR 給資料的頻率不固定,面試官看資料的時長也不固定,面試官只需要在固定時間內(nèi)看完給結(jié)論即可,不會有那么大的壓力。
使用 MQ 的壞處
名詞 | 解釋 |
---|---|
引入復(fù)雜度 | 「桌子」這東西是使用 MQ 后多出來的,需要有地方放桌子,而且流程會變長,更復(fù)雜 |
不一致性 | HR會以為面試官應(yīng)該看了資料,但實際面試官可能還沒開始看,這就導(dǎo)致了不一致性的問題,但在約束好的時間內(nèi),面試官最終的查閱狀態(tài)與HR的認(rèn)知必須是要一致的,這就是所謂的最終不一致性 |
系統(tǒng)可用性降低 | 如果桌子壞了,后面的流程是不是就中斷了 |
當(dāng)然,使用MQ
還有很多問題要解決,比如資料無辜丟了、一樣的資料,給了好多份、資料被搶、本來資料給面試官 A,結(jié)果給到面試官 B等場景都是需要處理的。
什么時候用 MQ
名詞 | 解釋 |
---|---|
生產(chǎn)者不需要從消費者處獲得反饋 | 面試官到底看了沒有,HR 根本不需關(guān)注,默認(rèn)面試官是看了,否則就只能采取監(jiān)督看完的方式 |
容許不一致性 | HR 可能會發(fā)現(xiàn)有時候面試官說看了資料,但實際沒看的情況,只有 HR 愿意相信面試官最后看了即可 |
有效 | 解耦、提速等帶來的收益大于放置書桌是有成本的,那說明是有效的。比如一個月甚至半年才有一份簡歷,那還不如直接當(dāng)面給更高效 |
消息模型
什么是 JMS
Java 消息服務(wù)指的是兩個應(yīng)用程序之間進行異步通信的 API,它為標(biāo)準(zhǔn)消息協(xié)議和消息服務(wù)提供了一組通用接口,包括創(chuàng)建、發(fā)送、讀取消息等,用于支持 JAVA 應(yīng)用程序開發(fā)。
為什么需要 JMS
在JAVA
中,如果兩個應(yīng)用程序之間對各自都不了解,甚至這兩個程序可能部署在不同地方上,那么它們之間如何發(fā)送消息呢?
舉個例子,一個應(yīng)用程序 A 部署在印度,另一個應(yīng)用程序部署在美國,然后每當(dāng) A 觸發(fā)某件事后,B 想從 A 獲取一些更新信息。
當(dāng)然,也有可能不止一個 B 對 A 的更新信息感興趣,可能會有 N 個類似 B 的應(yīng)用程序想從 A 中獲取更新的信息。
在這種情況下,JAVA
提供了最佳的解決方案-JMS
,完美解決了上面討論的問題。
點對點模型
在該模型中,有下列概念:
消息隊列 (Queue)、發(fā)送者 (Sender)、接收者 (Receiver)
每個消息都被發(fā)送到一個特定的隊列,接收者從隊列中獲取消息。隊列保留著消息,直到它們被消費或超時。
- 支持存在多個消費者
- 每個消息只有一個消費者(一旦消息被消費,消息就不再在消息隊列中)
- 發(fā)送者和接收者之間在時間上沒有依賴性,也就是說當(dāng)發(fā)送者發(fā)送了消息之后,不管接收者有沒有正在運行,它不會影響到消息被發(fā)送到隊列
- 接收者在成功接收消息之后需向隊列應(yīng)答成功
如果希望發(fā)送的每個消息都應(yīng)該被成功處理的話,那么就需要點對點模型。
女神想找備胎 A 聊天,就單聊備 A,這就是點對點,只有一個人能收到消息
發(fā)布訂閱模型
消息生產(chǎn)者(發(fā)布)將消息發(fā)布到topic
中,同時有多個消息消費者(訂閱)消費該消息。和點對點方式不同,發(fā)布到 topic 的消息會被所有訂閱者消費。。
在該模型中,有下列概念:
主題(Topic)、發(fā)布者(Publisher)、訂閱者(Subscriber)
客戶端將消息發(fā)送到主題。多個發(fā)布者將消息發(fā)送到 Topic,系統(tǒng)將這些消息傳遞給多個訂閱者。
- 每個消息可以有多個消費者
- 發(fā)布者和訂閱者有時間依賴性,只有當(dāng)客戶端創(chuàng)建訂閱后才能接受消息,且訂閱者需一直保持活動狀態(tài)以接收消息
- 訂閱者創(chuàng)建一個可持久化的訂閱。這樣,即使訂閱者沒有被激活(運行),它也能接收到發(fā)布者的消息。
如果希望發(fā)送的消息可以不被做任何處理、或者被一個消費者處理、或者可以被多個消費者處理的話,那么可以采用 Pub/Sub 模型。。
女神發(fā)了個朋友圈,她的備胎們都能看到,這就是發(fā)布/訂閱。
兩個模型之間的區(qū)別
點對點模型下,不可重復(fù)消費。
點對點下,一個隊列可以有多個消費者,生產(chǎn)者發(fā)送一條消息到隊列,消費者能用隊列取出并且消費消息,一旦消息被消費后,隊列不再有存儲,所以其他消費者不能消費到已經(jīng)被消費的消息,如果一直沒有消費者處理,這條消息就會被保存,直到有可用的消費者為止。
發(fā)布訂閱模型,可以重復(fù)消費。
發(fā)布訂閱下,發(fā)布者發(fā)送到 topic 的消息,只有訂閱了 topic 的訂閱者才會收到消息,注意是所有訂閱這個 topic 的服務(wù)都能收到,所以能達到消息拷貝的效果
MQ 的在工作上應(yīng)用場景
雖然上面以一個招聘的例子來講解 MQ 的應(yīng)用場景,但可能還是會有疑問,不知道工作上是如何的,因此再講講工作上的場景。
異步
之前負責(zé)的一個需求叫老帶新,大致流程如下:
1)用戶下單后,會先判斷下單者身份
2)如果是新用戶,再判斷是否有邀請人
3)如果有,再判斷邀請人身份
4)如果是老用戶,就給雙方發(fā)積分
這樣的話,用戶的流程就會發(fā)生變化:
很明顯,這樣做的問題是:新增的邏輯存在堵塞下單主流程的風(fēng)險。
既然同步處理會有問題,那就改異步吧,改完變成這樣:
異步的好處是,即使老帶新邏輯有問題,也不會堵塞下單流程。
這樣的好日子沒過幾天,問題又來了:老帶新業(yè)務(wù)頻繁改動,導(dǎo)致下單系統(tǒng)頻繁發(fā)版本,存在質(zhì)量隱患。
使用 MQ
由于依賴訂單系統(tǒng)的業(yè)務(wù)越來越多,為了保證下單系統(tǒng)的穩(wěn)定性,業(yè)務(wù)層面必須解耦,只需要把支付成功的消息告訴別的業(yè)務(wù),他們收到了通知后自行處理,我們只管自己的流程,后續(xù)還有其他業(yè)務(wù)系統(tǒng),直接訂閱我們發(fā)送的支付成功消息。
「MQ 帶來的問題」
- 如何保證消息隊列的高可用?
- 如何保證消息不被重復(fù)消費?
- 如何處理消息丟失的問題?
- 如何保證消息的順序性?
- 如何處理消息隊列大量消息積壓?
上面這些問題,都是實際工作上會遇到的,往往也都是測試點,下面也會有提及到,簡單了解下即可。
「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ù)是否有成功推動到對應(yīng)的 topic
- 推送失敗時如何處理
- 重復(fù)推送同一條數(shù)據(jù),如何處理
- 不同順序推送消息,注意隊列優(yōu)先級
- 推消息耗時
- 隊列容量達到上限,無法推送后如何處理
消費者
- 消費的消息是否來自訂閱的 topic
- 消息被消費了,是否有清除
- 生產(chǎn)者推送過快,消費速度過慢(堵塞),會如何
- 無法消費沒訂閱的 topic 消息
- 生產(chǎn)者推送消息后,消費者接受到的消息內(nèi)容跟生產(chǎn)者推的一致
- 如何處理重復(fù)消息,比如冪等
- 處理超時
- 消息處理失敗
- 消費消息的優(yōu)先級是否跟推的一致
- 消費消息耗時
- 消費者宕機,消息堆積,無人處理,會如何處理
- 是否能正常消費消息
隊列
- 宕機恢復(fù)后,消息是否丟失
- 宕機預(yù)案,多久能恢復(fù),如果無法恢復(fù)的預(yù)案
- 不同的消息格式,是否能正常識別及轉(zhuǎn)發(fā)
小結(jié)
來來去去,花了一周的時間來整理這堆信息,之前有測過mq,但沒有太了解這玩意,從介紹、選型、測試點,加深了對 mq 的印象,但由于沒做過 mq 的性能測試跟自動化測試,所以這塊暫時沒有心得能輸出,如果后續(xù)有類似的經(jīng)歷,也會分享下。
本文留下了一個懸念,針對消息不一致的問題,大家是怎么解決的,這邊非常好奇,所以下篇計劃會寫分布式事務(wù),想深入了解下細節(jié)~更多關(guān)于MQ工作場景消息模型的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
SpringCloud的@RefreshScope 注解你了解嗎
這篇文章主要介紹了Spring Cloud @RefreshScope 原理及使用,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2021-09-09MyBatis中的關(guān)聯(lián)關(guān)系配置與多表查詢的操作代碼
本文介紹了在MyBatis中配置和使用一對多和多對多關(guān)系的方法,通過合理的實體類設(shè)計、Mapper接口和XML文件的配置,我們可以方便地進行多表查詢,并豐富了應(yīng)用程序的功能和靈活性,需要的朋友可以參考下2023-09-09Java中replace與replaceAll的區(qū)別與測試
replace和replaceAll是JAVA中常用的替換字符的方法,下面這篇文章主要給大家介紹了關(guān)于Java中replace與replaceAll的區(qū)別與測試,文中通過實例代碼介紹的非常詳細,需要的朋友可以參考下2022-09-09一文學(xué)會如何在SpringBoot中使用線程池執(zhí)行定時任務(wù)
在開發(fā)現(xiàn)代應(yīng)用程序時,定時任務(wù)是一項常見的需求,SpringBoot提供了一個強大的定時任務(wù)框架,可以輕松地執(zhí)行各種定時任務(wù),結(jié)合線程池的使用,可以更好地管理任務(wù)的執(zhí)行,提高系統(tǒng)的性能和穩(wěn)定性,本文將介紹如何在Spring Boot中使用線程池執(zhí)行定時任務(wù)2023-06-06