mq要如何處理訊息丟失、重複消費?
如果要你實現一個支付寶向餘額寶轉賬的功能,比如:賬戶a從支付寶轉出5000餘額寶轉入5000,該怎麼做呢?
可能有些人會說,這還不簡單,直接上圖
支付寶先給賬戶a減5000,呼叫餘額寶的介面給餘額寶的賬號b加5000。
用這種方式正常情況下是可以的,如果出現以下問題該怎麼辦呢?
- 呼叫餘額寶api時網路失敗了
- 呼叫餘額寶api時網路超時了
- 如果餘額寶api業務邏輯比較複雜,耗時比較長,使用者需要長時間的等待才有結果,使用者體驗不好
有人說:如果呼叫餘額寶api時網路失敗了,對介面進行重試不就可以解決問題了。
答:你是用同步重試,還是非同步重試呢?
如果用同步重試,即在呼叫餘額寶api時獲取返回值,如果發現失敗立刻重試3次。呼叫一次餘額寶api的耗時為n秒,重試3次的耗時則為3n秒,介面響應時間增加了兩倍,增加了介面超時的風險。如果重試3次之後,還是失敗該怎麼處理?
如果用非同步重試,第一次呼叫餘額寶api時,不管是成功還是失敗,都直接給使用者返回成功。如果是失敗,後臺開啟一個執行緒,不斷重試一直到成功為止。如果在不斷重試的過程中伺服器重啟了,該怎麼辦?
又有人說:如果呼叫餘額寶api時網路超時了,不知道上次請求是成功還是失敗,再重試一下不行嗎?
答:不是不行,第一.餘額寶必須做冪等性設計,不然餘額寶這邊多轉入5000怎麼辦?餘額寶肯定不會犯這種錯誤。第二.同樣會面臨如果呼叫餘額寶api時網路失敗了的問題。
再有人說:如果餘額寶api業務邏輯比較複雜,耗時比較長,使用者需要長時間的等待才有結果,使用者體驗不好。改成非同步就可以解決這個問題了。
答:改成非同步可以提前告知使用者結果,然後在後臺通過補償機制不斷的重試,讓資料達成最終一致性,這種方式對使用者體驗可能確實要好一些。非同步處理又分為:開啟執行緒 和 使用mq。執行緒處理有比較致命的弊端,如果伺服器重啟,執行緒裡的資料會丟失。
接下來,我們的重點放在mq上。
餘額寶給賬戶a減了5000之後,給指定topic1發一條訊息,然後餘額寶從topic1消費這條訊息,給賬戶b加5000。
對於問題1,如果餘額寶處理失敗了,比如像rocketmq這類訊息處理框架會把訊息放入重試佇列重試16次,不需要業務程式碼做額外的工作。
對於問題2,如果伺服器重啟了,由於訊息儲存在服務端的磁碟上,不會丟失,客戶端可以通過offset從服務端重新獲取訊息,它能夠保證訊息至少被餘額寶消費一次。
對於問題3,支付寶給賬戶a減了5000傳送完訊息之後,可以直接返回成功,然後餘額寶作為消費者在後臺默默執行,一直到成功為止。
那麼問題又來了:
如果餘額寶消費了訊息,業務處理失敗了怎麼辦?這個就是所謂的訊息丟失。
要解決訊息丟失就需要建一張訊息傳送表,如圖:
支付寶從賬戶a減5000,接著往本地訊息表中寫入一條訊息記錄,confirm_status為待確認,然後傳送mq訊息。注意,支付寶這邊的扣款和寫本地訊息表要在同一事務中。
餘額寶消費訊息給賬戶b加5000之後,呼叫支付寶訊息確認api,修改confirm_status為已確認。
如果餘額寶這邊訊息丟失了,支付寶有個job會每個5分鐘掃描一次本地訊息表中confirm_status為待確認狀態的記錄,重新傳送一次訊息,這樣餘額寶又可以重新處理了。
那麼還有個問題:
餘額寶這邊處理成功,但是由於呼叫 支付寶訊息確認api失敗,導致支付寶的job重新傳送訊息,餘額寶重複消費了。這個就是所謂的重複訊息。
重複消費要如何解決呢?
餘額寶也增加一個本地訊息表,記錄業務處理成功的訊息。當然餘額寶的賬號操作和本地訊息表也要在同一個事務中。
餘額寶消費訊息之後,先從餘額寶的本地訊息表中查一下,該訊息有沒有消費過,如果已經消費過了,則直接呼叫支付寶訊息確認api,修改confirm_status為已確認,避免下次支付寶的job重複發訊息。如果從餘額寶的本地訊息表中查到沒有消費,則給賬戶b增加5000,同時往本地訊息表寫一條記錄,然後呼叫支付寶訊息確認api。
總結:通過在mq的生產者和消費者兩端分別增加本地訊息表,並且在生成者端增加定時job掃描待確認狀態的記錄,重新傳送訊息,可以解決:訊息丟失 和 重複消費 問題。當然實際的支付寶向餘額寶轉賬的場景更復雜,在高併發的情況下,可能需要用分散式鎖,防止金額異常
相關文章
- 實際業務處理 Kafka 訊息丟失、重複消費和順序消費的問題Kafka
- Spring Cloud Stream如何處理訊息重複消費?SpringCloud
- 解決RabbitMQ訊息丟失與重複消費問題MQ
- 《RabbitMQ》如何保證訊息不被重複消費MQ
- MQ 如何防止訊息重複入隊MQ
- 如何處理RabbitMQ 訊息堆積和訊息丟失問題MQ
- Kafka重複消費和丟失資料研究Kafka
- 訊息佇列-如何保證訊息的不被重複消費(如何保證訊息消費的冪等性)佇列
- 消費端如何保證訊息佇列MQ的有序消費佇列MQ
- 分散式訊息佇列:如何保證訊息不被重複消費?(訊息佇列消費的冪等性)分散式佇列
- 訊息中介軟體消費到的訊息處理失敗怎麼辦?
- 關於MQ的幾件小事(三)如何保證訊息不重複消費MQ
- 訊息中介軟體—RocketMQ訊息消費(三)(訊息消費重試)MQ
- MQ消費失敗,自動重試思路MQ
- MQ系列10:如何保證訊息冪等性消費MQ
- RabbitMQ,RocketMQ,Kafka 事務性,訊息丟失和訊息重複傳送的處理策略MQKafka
- RabbitMQ如何解決被重複消費和資料丟失的問題?MQ
- 阿里面試題剖析,如何保證訊息不被重複消費?阿里面試題
- Kafka中消費者延遲處理訊息Kafka
- Kafka 訊息丟失與消費精確一次性Kafka
- kafka 如何保證不重複消費又不丟失資料?Kafka
- 關於MQ的幾件小事(四)如何保證訊息不丟失MQ
- JMS訊息在消費者處於叢集環境下如何過濾重複資料
- 使用 Java API 處理 WebSphere MQ 大訊息JavaAPIWebMQ
- 阿里二面:要保證訊息不丟失,又不重複,訊息佇列怎麼選型?阿里佇列
- MQ收到無序的訊息時如何進行業務處理MQ行業
- RabbitMq如何確保訊息不丟失MQ
- RabbitMQ:訊息丟失 | 訊息重複 | 訊息積壓的原因+解決方案+網上學不到的使用心得MQ
- kafka 消費組功能驗證以及消費者資料重複資料丟失問題說明 3Kafka
- RabbitMQ防止訊息丟失MQ
- RabbitMQ-如何保證訊息不丟失MQ
- kafka消費者消費訊息的流程Kafka
- 【MQ】java 從零開始實現訊息佇列 mq-02-如何實現生產者呼叫消費者?MQJava佇列
- RocketMQ訊息丟失解決方案:事務訊息MQ
- 使用SpringCloud Stream結合rabbitMQ實現訊息消費失敗重發機制SpringGCCloudMQ
- Kafka消費者自動提交配置會導致潛在的重複或資料丟失!Kafka
- RocketMQ -- 訊息消費過程MQ
- Spring Cloud Stream消費失敗後的處理策略(一):自動重試SpringCloud