1. 消息隊列 Message Queue
內容包含記錄了對於主題與隊列、消息隊列的一致性、消息的丟失、重複、積壓問題
2. 為什麼需要消息隊列
2.1. 工廠流水線
大家在廠線上,只需要觀注自己的工作內容,意味著解耦了彼此的關係。
2.2. 水庫
當發生大量的請求與流量時,可以保護我們的後端伺服器的穩定,扮演水庫角色,進行的控制與排放。
2.3. 倉庫
可用途儲存半成品的存放站,後續再由它人去拿取半成品商品進行處理。
3. 場景
3.1. 非同步處理
同步處理
響應一個用戶的請求,需要完成4個步驟,每個模塊都有自己的運行時間,這樣的話運行時間就會相對較長。
並且,往往在過程當中,只有一步或二步是重要的關鍵步驟,其餘的步驟往往都沒有那麼重要…比如發郵件或簡訊通知訂單完成之類的訊息
亦或者是數據統計之類的工作。
異步處理
加入了隊列請求後,對於一個用戶的請求,我們只需要完成一個最核心的業務邏輯操作,完成後直接返回請求。
我們引入消息隊列,使這些模塊監聽消息隊列中的事件,這些模塊只要異步操作完即可。
異步處理,可以大大縮短響應用戶的請求
3.2. 應付瞬間巨量
秒殺活動流量較大,透過網關導向到隊列中,隊列在這當中扮演了很大的保護作用,可避免後端服務器崩潰。![MQ_流量控制](E:\1. kite\GitWorkSpace\kite_hexo\source_posts\2022-07-26 消息隊列.assets\MQ_流量控制.png)
3.3. 系統間解耦(服務解耦)
如果沒有導入MessageQueue
時,可以說每個模塊之間的接口耦合,又或者說每個微服務之間的RPC耦合。
如果某一個模塊出現了問題,又或者需要重新佈署,這些與它相依賴的模塊有可能會受到影響。
引入了MessageQueue之後,每個模塊就可以觀注在自己的事情上面,完全不用考慮體會上游或下游的情況。去掉耦合之後,我們的微服務佈署也好,項目維護也好,包括項目的高可用性,帶來不錯的效益。
4. 消息隊列類型
分為兩大類,分為單播、廣播。現在有很多消息隊列是能同時支援兩種類型的,比如RabbitMQ
、Kafka
4.1. 單播 (1對1)
一個消息發佈者
對應一個消息消費者
,就算MQ
中有多個消息,每一個消息都還是對應一個消息消費者
。很像我們平常在用的數據模式,先進先出。
4.2. 廣播 (1對多)
多個消息消費者
監聽一個消息發佈者
。舉例來說,一個訂單成立之後,後續流程各自展開「開始通知整貨作業、簡訊通知訂單成立、郵件通知訂單成立、統計數據」,多個模塊都需要知道一個消息發佈者的完整訊息。
5. 事務
什麼是事務,簡單來說它是一組操作,需要滿足這些操作全部完成或者這些操作全部都沒有完成
5.1. Half Message - RocketMQ
我們無法保證網路傳輸是穩定的,因此,如何提高事務的完整性(ACID,Atomicity 原子性 ),就需要透過一些設計方法與思維,其中,Half Message就是一個解決方法。它是一個有順序流程性的設計:
在開始執行業務邏輯之前,會先發送一條半消息到
MQ
,提醒MQ
說我們的業務邏輯即將開始了。MQ
會回覆收到半消息
的確認,如果這一步就錯誤了,我們就必須在業務邏輯上註記(返回)失敗。真正開始業務邏輯(這段覺得很怪
業務模組
告訴消息發佈者
)由消息發佈者進行提交/回滾消息給
MQ
,當MQ
收到提交(業務邏輯執行成功),則將半消息
改狀態變為正常的消息(可見的)消費消費者
自然可以去取得MQ
的訊息確認如何畫圖
而半消息
的定義是這條訊息在消費者那邊是不可見的。
5.1.1. 死信隊列
以上5個步驟只是確保MQ
、Publisher
、業務
的原子性
,無法確保Consumer
的原子性。因此,在Consumer與MQ之間,會允許嘗試try catch 多次(maybe 3~5次的限制),如果是失敗3次了,則進入到死信的隊列。其實死信隊列就是記錄了consumer操作失敗訊息,我們可以定期查詢死信隊列的記錄,進行手動修復,這樣就是最大成度的保證原子性。
5.1.2. 反查機制
我們繼續考慮一個例外狀況,當第4步驟沒有執行的時候,那MQ就會無法得知實際狀況,變成死等。因此,我們可以利用一個回調函式提供MQ去反查確認消費發佈者的狀況,maybe是一個定期器,預計10秒內應該得到回應,如果沒有就去反查消費發佈者
6. 消息隊列常見問題
6.1. 消息丟失
P 發送 MQ
MQ發送確認P
MQ發送C
C發送確認MQ
6.2. 重複消息
幂等性:Idempotence
重傳保證結果不會影響最終結果
6.3. 消息積壓
- 水平擴容queue/partition的數量,以及consumer實例的數量
- 兩邊要等量的增加,單獨增加一邊是沒有效益的
- 排查日誌,確保隊列層正常送達消息
- 在producer段,服務降級
- 提供重要邏輯的優先度