MQ不丟訊息,究竟是怎麼實現的?

架構師修行之路發表於2020-06-04

前幾天有水友提問:
透過訊息佇列(MsgQueue,MQ)傳送任務和訊息萬一MQ重啟了怎麼辦?能否保證MQ不丟訊息?

今天就聊聊MQ的訊息必達性架構與流程。

不丟訊息,MQ架構設計的核心方向是什麼?
MQ要想訊息必達,架構上有兩個核心設計點:
(1)訊息落地
(2)訊息超時、重傳、確認

為了實現上述兩個核心點,MQ架構如何?
MQ不丟訊息,究竟是怎麼實現的?
上圖是一個MQ的核心架構圖,可以分為三大塊:
(1)傳送方 -> 左側粉色部分;
(2)MQ核心叢集 -> 中間藍色部分;
(3)接收方 -> 右側屎黃色部分;

粉色傳送方又由兩部分構成:
(1)業務呼叫方;
(2)MQ-client-sender;
其中後者向前者提供了兩個核心API

(1)SendMsg(bytes[] msg);

(2)SendCallback();


藍色MQ核心叢集又分為四個部分:

(1)MQ-server

(2)zk;

(3)db;

(4)管理後臺web;


黃色接收方也由兩部分構成:
(1)業務接收方;
(2)MQ-client-receiver;
其中後者向前者提供了兩個核心API

(1)RecvCallback(bytes[] msg);

(2)SendAck();


MQ是一個系統間解耦的利器,它能夠很好的解除釋出訂閱者之間的耦合,它將上下游的訊息投遞解耦成兩個部分,如架構圖中的1箭頭和2箭頭:

MQ不丟訊息,究竟是怎麼實現的?
箭頭1:傳送方將訊息投遞給MQ,上半場;
箭頭2:MQ將訊息投遞給接收方,下半場;

MQ訊息可靠投遞核心流程如何?
MQ既然將訊息投遞拆成了上下半場,為了保證訊息的可靠投遞,上下半場都必須保證訊息必達。
MQ不丟訊息,究竟是怎麼實現的?
MQ訊息投遞上半場,MQ-client-sender到MQ-server流程見上圖1-3:
(1)MQ-client將訊息傳送給MQ-server;
畫外音:此時業務方呼叫API:SendMsg。
(2)MQ-server將訊息落地,落地後即為傳送成功;
(3)MQ-server將應答傳送給MQ-client;
畫外音:此時回撥業務API:SendCallback。

MQ不丟訊息,究竟是怎麼實現的?
MQ訊息投遞下半場,MQ-server到MQ-client-receiver流程見上圖4-6:
(4)MQ-server將訊息傳送給MQ-client;
畫外音:此時回撥業務API:RecvCallback。
(5)MQ-client回覆應答給MQ-server;
畫外音:此時業務方主動呼叫API:SendAck。
(6)MQ-server收到ack,將之前已經落地的訊息刪除,完成訊息的可靠投遞;

如果訊息丟了怎麼辦?
MQ訊息投遞的上下半場,都可以出現訊息丟失,為了保證訊息可達性,MQ需要進行超時和重傳。

上半場如何實施超時與重傳?
MQ不丟訊息,究竟是怎麼實現的?
MQ上半場的1或者2或者3如果丟失或者超時,MQ-client-sender內的timer會重發訊息,直到期望收到3,如果重傳N次後還未收到,則SendCallback回撥傳送失敗,需要注意的是,這個過程中MQ-server可能會收到同一條訊息的多次重發。

下半場如何實施超時與重傳?
MQ不丟訊息,究竟是怎麼實現的?
MQ下半場的4或者5或者6如果丟失或者超時,MQ-server內的timer會重發訊息,直到收到5並且成功執行6,這個過程可能會重發很多次訊息。
畫外音:一般採用指數退避的策略,先隔x秒重發,2x秒重發,4x秒重發,以此類推。
需要注意的是,這個過程中MQ-client-receiver也可能會收到同一條訊息的多次重發。

總結
MQ是系統之間的解耦利器,MQ為了保證訊息必達,架構設計方向為:
(1)訊息收到先落地;
(2)訊息超時、重傳、確認保證訊息必達;


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69959420/viewspace-2696097/,如需轉載,請註明出處,否則將追究法律責任。

相關文章