保證消息的可靠性投遞和消費,將分為兩部分來進行,第一部分來描述消息的可靠性投遞,包含目前流行的兩種可靠性投遞架構,第二部分將描述消息的可靠性消費,包含消息冪等性介紹等。第三部分將結合RabbitMQ來講述下怎么保證消息不丟失。通過本篇的學習,可以學習到消息可靠性的投遞、消費以及怎樣保證消息不丟失。
消息可靠性投遞
執行步驟:
1. 保障消息成功發出
2. 保證MQ節點成功接收
3. 發送端收到消費端的確認應答
4. 完善的消息補償機制
解決方案:
1. 業務和消息同時入庫,對消息進行處理修改標記
2. 消息延遲投遞,做二次確認,回調檢查
可靠性投遞方案一:消息入庫,對消息打標
1. 流程圖如下
2. 流程拆解
①:消息和業務記錄入庫
②:第一步正常執行完后,將消息發送個MQ
③:消息處理完,發送確認消息給MQ
④:更新消息的狀態
⑤:定時任務讀取消息的狀態
⑥:如果消息處理工程,流程結束,否則讀消息重發MQ
⑦:重試次數內,重復執行流程;超過重試次數,將數據庫更新狀態
⑧:補償系統,解決超過重試次數消息,保障消息的100%投遞
3. 方案問題
兩次數據入庫,不適合在高並發場景使用。
可靠性投遞方案二:消息延遲發送,做二次檢查,回調檢查
1. 流程圖如下
2. 流程拆解
①:業務記錄入庫,業務記錄正常入庫后向MQ發送消息
②:第二次消息延遲3-5分鍾,向MQ發送消息
③:消費監聽隊列,消費消息
④:消費者消費完后,發送確認消息給MQ的一個隊列
⑤:另外一個服務監聽消費者發送的confirm消息,如果正常完成,消息入庫。
⑥:另外服務,經停延遲發送的隊列,那消息檢查msg數據庫,如果沒有,將再msg上新插入一條消息,用來記錄重試次數
⑦:延遲檢查成功,不需要任何操作;如果檢查不成功,將通知服務,重新發消息給MQ
⑧:補償系統,解決超過重試次數消息,保障消息的100%投遞
消息可靠性消費-不重復消費
消息保證不重復消費,就要保證消息的冪等性,什么是冪等性?
冪等性:指消息執行一次和執行多次的結果相同,就說明消息是冪等的。
保證消息冪等性:
1. 通過數據庫主鍵形式(ID+指紋碼)
2. 使用Redis原子性保證冪等性
保證冪等性方案一:通過數據庫主鍵形式(ID+指紋碼)
指紋碼:是唯一的系統碼,可以是內部規則(如時間戳)和外部返回(如銀行流水號),通過指紋碼和全局唯一ID做主鍵,利用數據庫主鍵進行去重。
使用指紋碼避免用戶在一個唯一主鍵可能因為網絡延遲等問題,對數據庫進行多次寫操作。
1. 實現
select * from table where id=唯一id+指紋碼
實現簡單,但在高並發情況下存在數據庫寫入性能的瓶頸。多余指紋碼加大主鍵長度影響存儲。
2. 解決方案
數據庫采用分庫分表,將id根據規則分布到不同的數據庫表中,單一數據庫分流降壓。
保證冪等性方案二:利用Redis原子性操作保證冪等性
1. 實現
這種性能高,Redis是基於內存,不會造成數據庫瓶頸。
2. 問題
①Redis數據庫是否需要入庫,怎樣保證數據庫和Redis中數據一致性(一般保證冪等是不需入庫)
②如果不入庫,怎樣保證定時清理策略,緩存得可靠性保證(高可用-集群,定期清理策略)
RabbitMQ保障消息的可靠性傳輸
可靠性傳輸就是保證不丟失數據,丟失數據一般分為兩部分,分別是MQ丟失數據,另外是我們生產消費消息時丟失數據。具體細分的包含生產者保證消息不丟失,MQ保證消息不丟失和消費者保證消息不丟失。
消息可靠性傳遞一:生產者保證消息不丟失
生產者保證數據不丟失可以采取兩種方式:
1. 使用RabbitMQ事務,在發送消息之前開啟事務(channel.txSelect),正常發送后提交事務(channel.txCommit),如果出現異常,需要回滾事務(channel.txRollback)做消息重發等操作
缺點:RabbitMQ事務采用同步的方式進行事務處理,提交一個事務后,事務阻塞在哪,只有等這個事務執行完才能執行下一個事務,嚴重影響RabbitMQ性能,在 實際生產中不使用。
2. 使用confirm模式,生產者開始confirm模式后,每次寫數據會分配唯一id,當消息成功處理,將回傳ack,消息處理失敗,回傳nack。
優點:采用異步模式,消費者發送一條消息后,不用等消息回傳消息,就可以發送下一條消息,RabbitMQ將異步接受這條回傳信息,如果是nack,將進行消息重試。實際生產中使用這種方式。
類型:普通Confirm模式 批量Confirm模式 異步Confirm模式,將再以后的博客中詳細介紹3中不同的confirm類型
消息可靠性傳遞二:RabbitMQ保證消息不丟失
保證RabbitMQ消息不丟失,需要兩步操作;
1. 創建queue時,將queue設置為持久化,
2. 發送消息的時,設置消息的deliveryMode=2。
即使這樣操作,還可能存在,消息寫到RabbitMQ中,但是消息沒有持久化磁盤,這是服務器重啟,這部分數據丟失。
消息可靠性傳遞三:消費者保證消息不丟失
消費端關閉自動應答,設置手動應答。
autoAck=false; 這樣保證消費者消費消息后,刪除RabbitMQ中數據。
小結
1. 兩種可靠性投遞,第一種執行簡單,但是不適合高並發環境;第二種執行復雜,但是減少一次數據入庫,性能會有提高,適合高並發環境。如果MQ所在的服務器宕機,MQ中沒有及時消費的數據會丟失
2. 保證冪等性可以采用兩種方式,第一種是主鍵方式,第二種采用Redis原子性,根據業務場景的不同來選擇。
3. 詳細講解RabbitMQ的消息可靠性傳遞,並從生產者,消費者和RabbitMQ來保證消息不丟失。