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