MQ 如何實現,消息冪等( MQ 真的不能再背鍋了)?
《MQ如何實現,消息必達?》消息必達,架構設計上有兩個核心設計點:
- 消息落地;
- 消息超時、重傳、確認;
但消息重傳可能導致reciever收到重復的消息,從而對業務產生影響。
MQ如何實現消息冪等呢?這還是得從MQ的消息發送流程說起。
如《MQ如何實現,消息必達?》所述,MQ能解除發布訂閱者之間的耦合,它將消息投遞解耦成上下兩個半場:
- 箭頭1,上半場:發送方將消息投遞給MQ;
- 箭頭2,下半場:MQ將消息投遞給接收方;
MQ要想實現冪等,上下半場都必須做到冪等。
上半場,如何做到冪等?
MQ消息投遞上半場,流程見上圖123:
- 1:sender將消息發送給MQ-server;
- 2:MQ-server將消息落地;
- 3:MQ-server回調sender;
如果步驟3超時,步驟1會重傳,會導致步驟2收到重復的消息。此時,
- 重發方是:MQ-client
- 接收方是:MQ-server
消息的收發在MQ系統內閉環,可以由MQ來實施消息冪等。
MQ如何實施消息冪等?
為了避免步驟2落地重復的消息,對每條消息,MQ系統內部必須生成一個inner-msg-id,作為去重和冪等的依據。
這個inner-msg-id的特性是:
- 全局唯一;
- 由MQ生成,具備業務無關性,對消息發送方和消息接收方都透明;
有了這個inner-msg-id,就能保證上半場重發,也只有1條消息落到MQ-server的DB中,實現上半場冪等。
下半場,如何做到冪等?
MQ消息投遞下半場,流程見上圖456:
- 4:MQ-server回調reciever;
- 5:reciever收到消息,處理業務邏輯,將ACK發送給MQ-server;
- 6:MQ-server收到ACK,將之前已經落地的消息刪除,流程結束;
如果步驟5超時,步驟4會重傳,會導致業務處理方收到重復的消息。此時,
- 重發方是:MQ-server
- 接收方是:業務處理方
消息的收發不能在MQ系統內閉環,只能由業務處理方來保證消息冪等。
業務處理方如何實施消息冪等?
在消息實體中,必須有一個biz-id,作為去重和冪等的依據,這個biz-id的特性是:
- 對于同一個業務場景,全局唯一;
- 由業務消息發送方生成,業務相關,對MQ透明;
- 由業務消息接收方負責判重,以保證冪等;
最常見的biz-id有:
- 訂單id,業務方有義務避免重復生成;
- 支付id,業務方有義務避免重復扣款;
- 帖子id,業務方有義務避免重復發布;
- ...
總結
MQ要想實現冪等,上下半場都必須做到冪等。
上半場:
- MQ-client生成inner-msg-id,保證上半場冪等;
- inner-msg-id全局唯一,業務無關,由MQ保證;
下半場:
- 業務發送方帶入biz-id,業務接收方去重保證冪等;
- 這個biz-id對業務唯一,業務相關,對MQ透明。
冪等性,不僅對MQ有要求,對業務上下游也有要求,那些罵MQ無法保證冪等的架構師,其實自己...
知其然,知其所以然。
思路比結論更重要。