mq要如何處理消息丟失、重復消費?


如果要你實現一個支付寶向余額寶轉賬的功能,比如:賬戶a從支付寶轉出5000余額寶轉入5000,該怎么做呢?

 

可能有些人會說,這還不簡單,直接上圖

 

 

 

支付寶先給賬戶a減5000,調用余額寶的接口給余額寶的賬號b加5000。

 

用這種方式正常情況下是可以的,如果出現以下問題該怎么辦呢?

  1. 調用余額寶api時網絡失敗了

  2. 調用余額寶api時網絡超時了

  3. 如果余額寶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掃描待確認狀態的記錄,重新發送消息,可以解決:消息丟失 和 重復消費 問題。當然實際的支付寶向余額寶轉賬的場景更復雜,在高並發的情況下,可能需要用分布式鎖,防止金額異常。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM