一文幫你瞭解 MQ
一、簡介
MQ 全稱爲 Message Queue - 消息隊列,是一種應用程序對應用程序的消息通信,一端只管往隊列不斷髮布信息,另一端只管往隊列中讀取消息,發佈者不需要關心讀取消息的誰,讀取消息者不需要關心發佈消息的是誰,各幹各的互不干擾。
市場上現在常用的消息隊列有:RabbitMQ、RocketMQ、Kafka,ActiveMQ
二、MQ 的優勢
(1) 解耦
使用消息 MQ 後,只需要保證消息格式不變,不需要關心發佈者及消費者之間的關係,這兩者不需要彼此聯繫
(2) 異步
在一些不需要即時 (同步) 的返回結果操作,通過消息隊列來實現異步。
(3) 削峯
在大量請求時 (秒殺場景),使用消息隊列做緩衝處理,削弱峯值流量,防止系統在短時間內被峯值流量沖垮。
場景:在大量流量湧入高峯,如數據庫只能抗住 2000 的併發流量,可以使用 MQ 控制 2000 到數據庫中
(4) 日誌處理
日誌存儲在消息隊列中,用來處理日誌,比如 kafka。
三、MQ 的劣勢
- 系統的可用性降低
在還未引進 MQ 之前,系統只需要關係生產端與消費端的接口一致性就可以了,現在引進後,系統需要關注生產端、MQ 與消費端三者的穩定性,這增加系統的負擔,系統運維成本增加。
- 系統的複雜性提高
引入了 MQ,需要考慮的問題就增加了,如何保障消息的一致性,消費不被重複消費等問題,
- 一致性問題
A 系統發送完消息直接返回成功,但是 BCD 系統之中若有系統寫庫失敗,則會產生數據不一致的問題。
四、常見的問題
(1) 怎麼保證消息沒有重複消費?使用消息隊列如何保證冪等性
冪等性:就是用戶對於同一操作發起的一次請求或者多次請求的結果是一致的,不會因爲多次點擊而產生了副作用
問題出現原因
我們先來了解一下產生消息重複消費的原因,對於 MQ 的使用,有三個角色:生產者、MQ、消費者,那麼消息的重複這三者會出現:
-
生產者:生產者可能會推送重複的數據到 MQ 中,有可能 controller 接口重複提交了兩次,也可能是重試機制導致的
-
MQ:假設網絡出現了波動,消費者消費完一條消息後,發送 ack 時,MQ 還沒來得及接受,突然掛了,導致 MQ 以爲消費者還未消費該條消息,MQ 回覆後會再次推送了這條消息,導致出現重複消費。
-
消費者:消費者接收到消息後,正準備發送 ack 到 MQ,突然消費者掛了,還沒得及發送 ack,這時 MQ 以爲消費者還沒消費該消息,消費者重啓後,MQ 再次推送該條消息。
解決方案
在正常情況下,生產者是客戶,我們很難避免出現用戶重複點擊的情況,而 MQ 是允許存在多條一樣的消息,但消費者是不允許出現消費兩條一樣的數據,所以冪等性一般是在消費端實現的:
-
狀態判斷:消費者把消費消息記錄到 redis 中,再次消費時先到 redis 判斷是否存在該數據,存在則表示消費過,直接丟棄
-
業務判斷:消費完數據後,都是需要插入到數據庫中,使用數據庫的唯一約束防止重複消費。插入數據庫前先查詢是否存在該數據,存在則直接丟棄消息,這種方式是比較簡單粗暴地解決問題
(2) 消息丟失的情況
(3) 消息的傳輸順序性
解決思路
在生產端發佈消息時,每次法發佈消息都把上一條消息的 ID 記錄到消息體中,消費者接收到消息時,做如下操作
-
先根據上一條 Id 去檢查是否存在上一條消息還沒被消費,如果不存在 (消費後去掉 id),則正常進行,如果正常操作
-
如果存在,則根據 id 到數據庫檢查是否被消費,如果被消費,則正常操作
-
如果還沒被消費,則休眠一定時間 (比如 30ms),再重新檢查,如被消費,則正常操作
-
如果還沒被消費,則拋出異常
(4) 怎麼解決百萬消息積壓問題
根據消息重要程度,可以分爲兩種情況處理
-
如果消息可以被丟棄,那麼直接丟棄就好了
-
一般情況下,消息是不可以被丟棄的,那麼這樣需要考慮策略了,我們可以把原來的消費端重新當做生產端,重新部署一天 MQ,再後面出現增加消費端,這樣形成另一條生產 - 消息 - 消費的線路
程序員追風 專注於分享 Java 各類學習筆記、面試題以及 IT 類資訊。
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/9OkkUoSALTaUm99yHP4nqA