MQ的消息模型及在工作上應用場景

MQ介紹

根據某科的介紹,MQ(message queue),叫消息隊列,是基礎數據結構中先進先出的一種數據機構。

一般用來解決應用解耦,異步消息,流量削鋒等問題,實現高性能,高可用,可伸縮和最終一致性架構。

名詞 解釋
解耦 簡單說就是積木化,每個東西都相互獨立,比如漢堡包,面包跟肉餅是相互獨立,可以單獨使用,也可以組合成一個食物
異步 去買漢堡包,下單之後就去玩手機,等服務員叫號通知領取,這就叫異步;而同步是下單後,什麼都不能幹,直到服務員叫號才能做其他事
限流 大傢 9 點上班,地鐵進不去,門口做限流
削峰 遵從最後落地到數據庫的請求數要盡量少的原則,比如讓 1/2 的人下午開始上班、局部停電,感興趣可以查看削峰填谷
消息 要傳輸的內容,比如說話、寫信,形式不重要,按照雙方約定的格式即可
隊列 是一種先進先出的數據結構,排隊打疫苗,從隊尾入隊,從隊頭出隊

MQ 主要產品包括:RabbitMQ、ActiveMQ、RocketMQ、ZeroMQ、Kafka

通過上述的內容,不難發現,MQ是一種跨進程的通信機制,用於上下遊傳遞消息,而個人覺得MQ有點像中介, 房東發佈出租信息,信息放在中介處,租客來通過中介來租房子。

使用 MQ 的好處

舉個通俗點的例子:

面試官希望 HR 早點招聘到合適的人選,於是一開始是這樣的:

HR 問面試官什麼時候有空,把候選人資料送過去,並且親自看到面試官看完並給出結論後才離開,時間一長,大傢都覺得很麻煩,HR 覺得候選人不錯,面試官覺得不合適,容易發生爭執。

後面,HR 跟面試官說,我把資料放在桌子上,你有空記得看,然後每次面試官看到桌子有資料後,都會拿起來看。

在這個場景上,HR就是生產者,面試官就是消費者,桌子就是MQ。

使用MQ帶來的好處是解決應用解耦,異步消息,流量削鋒:

  • HR想給資料時,無需知道面試官是否有空,隻需要把資料放桌子上即可,這樣大傢都有時間做別的事,節省大傢的時間。。應用解耦,每個成員都是獨立的,不受其他成員影響。面試官不關心誰放的資料,HR 不關心誰哪個面試官看的資料
  • 如果別的組也有招聘需求(且當是同一工種,比如 Java 後端開發),HR依然把資料放在桌子上,兩個面試官隻需要各自從桌子上取資料查閱即可。異步消息,HR 把資料放在桌子上即可,就可以去做別的事,比一開始親自看著的效率高太多瞭
  • HR無需關註面試官什麼時候查看資料,也不關註看資料用多長的時間,減少矛盾。流量削峰,HR 給資料的頻率不固定,面試官看資料的時長也不固定,面試官隻需要在固定時間內看完給結論即可,不會有那麼大的壓力。

使用 MQ 的壞處

名詞 解釋
引入復雜度 「桌子」這東西是使用 MQ 後多出來的,需要有地方放桌子,而且流程會變長,更復雜
不一致性 HR會以為面試官應該看瞭資料,但實際面試官可能還沒開始看,這就導致瞭不一致性的問題,但在約束好的時間內,面試官最終的查閱狀態與HR的認知必須是要一致的,這就是所謂的最終不一致性
系統可用性降低 如果桌子壞瞭,後面的流程是不是就中斷瞭

當然,使用MQ還有很多問題要解決,比如資料無辜丟瞭、一樣的資料,給瞭好多份、資料被搶、本來資料給面試官 A,結果給到面試官 B等場景都是需要處理的。

什麼時候用 MQ

名詞 解釋
生產者不需要從消費者處獲得反饋 面試官到底看瞭沒有,HR 根本不需關註,默認面試官是看瞭,否則就隻能采取監督看完的方式
容許不一致性 HR 可能會發現有時候面試官說看瞭資料,但實際沒看的情況,隻有 HR 願意相信面試官最後看瞭即可
有效 解耦、提速等帶來的收益大於放置書桌是有成本的,那說明是有效的。比如一個月甚至半年才有一份簡歷,那還不如直接當面給更高效

消息模型

什麼是 JMS

Java 消息服務指的是兩個應用程序之間進行異步通信的 API,它為標準消息協議和消息服務提供瞭一組通用接口,包括創建、發送、讀取消息等,用於支持 JAVA 應用程序開發。

為什麼需要 JMS 

JAVA中,如果兩個應用程序之間對各自都不瞭解,甚至這兩個程序可能部署在不同地方上,那麼它們之間如何發送消息呢?

舉個例子,一個應用程序 A 部署在印度,另一個應用程序部署在美國,然後每當 A 觸發某件事後,B 想從 A 獲取一些更新信息。

當然,也有可能不止一個 B 對 A 的更新信息感興趣,可能會有 N 個類似 B 的應用程序想從 A 中獲取更新的信息。

在這種情況下,JAVA提供瞭最佳的解決方案-JMS,完美解決瞭上面討論的問題。

點對點模型

在該模型中,有下列概念:
消息隊列 (Queue)、發送者 (Sender)、接收者 (Receiver)

每個消息都被發送到一個特定的隊列,接收者從隊列中獲取消息。隊列保留著消息,直到它們被消費或超時。

  • 支持存在多個消費者
  • 每個消息隻有一個消費者(一旦消息被消費,消息就不再在消息隊列中)
  • 發送者和接收者之間在時間上沒有依賴性,也就是說當發送者發送瞭消息之後,不管接收者有沒有正在運行,它不會影響到消息被發送到隊列
  • 接收者在成功接收消息之後需向隊列應答成功

如果希望發送的每個消息都應該被成功處理的話,那麼就需要點對點模型。

女神想找備胎 A 聊天,就單聊備 A,這就是點對點,隻有一個人能收到消息

發佈訂閱模型

消息生產者(發佈)將消息發佈到topic中,同時有多個消息消費者(訂閱)消費該消息。和點對點方式不同,發佈到 topic 的消息會被所有訂閱者消費。。

在該模型中,有下列概念:
主題(Topic)、發佈者(Publisher)、訂閱者(Subscriber)

客戶端將消息發送到主題。多個發佈者將消息發送到 Topic,系統將這些消息傳遞給多個訂閱者。

  • 每個消息可以有多個消費者
  • 發佈者和訂閱者有時間依賴性,隻有當客戶端創建訂閱後才能接受消息,且訂閱者需一直保持活動狀態以接收消息
  • 訂閱者創建一個可持久化的訂閱。這樣,即使訂閱者沒有被激活(運行),它也能接收到發佈者的消息。

如果希望發送的消息可以不被做任何處理、或者被一個消費者處理、或者可以被多個消費者處理的話,那麼可以采用 Pub/Sub 模型。。

女神發瞭個朋友圈,她的備胎們都能看到,這就是發佈/訂閱。

兩個模型之間的區別

點對點模型下,不可重復消費。

點對點下,一個隊列可以有多個消費者,生產者發送一條消息到隊列,消費者能用隊列取出並且消費消息,一旦消息被消費後,隊列不再有存儲,所以其他消費者不能消費到已經被消費的消息,如果一直沒有消費者處理,這條消息就會被保存,直到有可用的消費者為止。

發佈訂閱模型,可以重復消費。

發佈訂閱下,發佈者發送到 topic 的消息,隻有訂閱瞭 topic 的訂閱者才會收到消息,註意是所有訂閱這個 topic 的服務都能收到,所以能達到消息拷貝的效果

MQ 的在工作上應用場景

雖然上面以一個招聘的例子來講解 MQ 的應用場景,但可能還是會有疑問,不知道工作上是如何的,因此再講講工作上的場景。

異步

之前負責的一個需求叫老帶新,大致流程如下:

1)用戶下單後,會先判斷下單者身份

2)如果是新用戶,再判斷是否有邀請人

3)如果有,再判斷邀請人身份

4)如果是老用戶,就給雙方發積分

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

很明顯,這樣做的問題是:新增的邏輯存在堵塞下單主流程的風險。

既然同步處理會有問題,那就改異步吧,改完變成這樣:

異步的好處是,即使老帶新邏輯有問題,也不會堵塞下單流程。

這樣的好日子沒過幾天,問題又來瞭:老帶新業務頻繁改動,導致下單系統頻繁發版本,存在質量隱患。

使用 MQ

由於依賴訂單系統的業務越來越多,為瞭保證下單系統的穩定性,業務層面必須解耦,隻需要把支付成功的消息告訴別的業務,他們收到瞭通知後自行處理,我們隻管自己的流程,後續還有其他業務系統,直接訂閱我們發送的支付成功消息。

「MQ 帶來的問題」

  • 如何保證消息隊列的高可用?
  • 如何保證消息不被重復消費?
  • 如何處理消息丟失的問題?
  • 如何保證消息的順序性?
  • 如何處理消息隊列大量消息積壓?

上面這些問題,都是實際工作上會遇到的,往往也都是測試點,下面也會有提及到,簡單瞭解下即可。

「MQ 產品的對比」

產品 單機吞吐量 時效性 可用性 消息可靠性 功能支持
ActiveMQ 萬級 毫秒級 較低概率出現丟失數據 極其完備
RabbitMQ 萬級 微妙級 基本不丟 erlang 開發
RocketMQ 十萬級 毫秒級 非常高 可配置 0 丟失 分佈式
Kafka 十萬級 毫秒級 非常高高 可配置 0 丟失 分佈式

而在選擇上,一般公司都是用KafkaRocketMQ較多。

「MQ 的測試點」

生產者

  • 生成的數據格式是否跟定義的一致
  • 數據是否有成功推送到隊列裡
  • 數據是否有成功推動到對應的 topic
  • 推送失敗時如何處理
  • 重復推送同一條數據,如何處理
  • 不同順序推送消息,註意隊列優先級
  • 推消息耗時
  • 隊列容量達到上限,無法推送後如何處理

消費者

  • 消費的消息是否來自訂閱的 topic
  • 消息被消費瞭,是否有清除
  • 生產者推送過快,消費速度過慢(堵塞),會如何
  • 無法消費沒訂閱的 topic 消息
  • 生產者推送消息後,消費者接受到的消息內容跟生產者推的一致
  • 如何處理重復消息,比如冪等
  • 處理超時
  • 消息處理失敗
  • 消費消息的優先級是否跟推的一致
  • 消費消息耗時
  • 消費者宕機,消息堆積,無人處理,會如何處理
  • 是否能正常消費消息

隊列

  • 宕機恢復後,消息是否丟失
  • 宕機預案,多久能恢復,如果無法恢復的預案
  • 不同的消息格式,是否能正常識別及轉發

小結

來來去去,花瞭一周的時間來整理這堆信息,之前有測過mq,但沒有太瞭解這玩意,從介紹、選型、測試點,加深瞭對 mq 的印象,但由於沒做過 mq 的性能測試跟自動化測試,所以這塊暫時沒有心得能輸出,如果後續有類似的經歷,也會分享下。

本文留下瞭一個懸念,針對消息不一致的問題,大傢是怎麼解決的,這邊非常好奇,所以下篇計劃會寫分佈式事務,想深入瞭解下細節~更多關於MQ工作場景消息模型的資料請關註WalkonNet其它相關文章!

推薦閱讀: