MQ系列1:訊息中介軟體執行原理
MQ系列2:訊息中介軟體的技術選型
MQ系列3:RocketMQ 架構分析
MQ系列4:NameServer 原理解析
MQ系列5:RocketMQ訊息的傳送模式
MQ系列6:訊息的消費
MQ系列7:訊息通訊,追求極致效能
MQ系列8:資料儲存,訊息佇列的高可用保障
MQ系列9:高可用架構分析
MQ系列10:如何保證訊息冪等性消費
這篇我們來說說 MQ 訊息的可靠性傳輸。可靠性傳輸其實包含兩種情況:一種是重複消費的情況,我們上一篇的冪等性消費解決的就是這個問題;另外一種是訊息丟失的情況的,要確保我們生產的訊息一定最終會得到消費。這時候就要從訊息執行的幾個階段去保證,每一個階段都不能出現問題。
訊息生產階段指的是訊息從生產到訊息傳送出去,經過網路傳輸,再到達Broker伺服器並被接收的這整個階段,我們需要一個健壯的確認機制(ACK)來保證訊息傳遞的可靠性。如果說訊息被接收到之後可以反饋給訊息生產方去確認,那這個過程就比較完美了。
Broker作為訊息伺服器,主要用於訊息收發的操作。一般情況下只要訊息服務正常執行,並依賴資料持久化能力,丟訊息的可能行就比較小。
但是在很多場景下,為了提升訊息佇列的效率,為了提升吞吐能力,在沒有確定完成持久化動作(刷盤)之前,就會把確認訊息返回。即只要訊息進行
Commit了,那就是成功的。但是如果還沒持久化成功便發生了宕機,那就有存在訊息丟失的風險。可以參照如下優化:
訊息儲存到了Broker之後,剩下的就是訊息消費了。訊息消費階段跟生產階段大概一致,都是使用確認機制來保證訊息的可靠性和傳輸的。
當Consumer從Broker拉取到訊息之後,開始消費訊息,執行業務的的邏輯程式,業務程式執行成功後,才給Broker傳送消費確認響應。
如果沒成功或者訊息在傳送中途丟失,就沒有確認響應,這樣的話,在下一輪訊息拉取的時候,Broker依舊會返回這一條消費資料給你,避免網路抖動原因或者Consumer在執行消費出錯導致丟失。
多個消費者消費用一個分割區,我們經常會出現這種情況:同一個Consumer Group 裡面有多個Consumer,比如Comsumer A 拉走了某一批資料,但是還沒返回確認訊息,Consumer B 又過來要 拉資料了,Broker要怎麼判定呢?
這邊舉個例子:Consumer A 拉取 index = 106 位置的資料,但是還沒返回消費完成的確認資訊,這時候消費位置依然是 index = 10086,如果 Consumer B 也過拉取資料,則
在RocketMQ中,當訊息第一次消費失敗時,訊息佇列會自動進行訊息重試,達到最大重試次數(可設定閾值,比如5)後,若消費依然失敗,則表明消費者在正常情況下無法正確地消費該訊息。此時,訊息佇列RocketMQ版不會立刻將訊息丟棄,而是將其傳送到該消費者對應的特殊佇列中。這種無法被消費的訊息稱為死信訊息(Dead-Letter Message),儲存死信訊息的特殊佇列稱為死信佇列(Dead-Letter Queue)。
可以使用單獨的作業服務進行獨立處理,比如重新傳送死信訊息進行消費,避免訊息漏處理導致業務服務可用性問題。
總得來說:MQ可以從三個角度來分析:生產者丟資料、訊息佇列伺服器(Broker)丟資料、消費者丟資料
生產者丟資料:RabbitMQ提供transaction和confirm模式來確保生產者不丟訊息。
訊息佇列服務丟資料:開啟持久化磁碟的設定。這個持久化設定可以和confirm機制配合使用,你可以在訊息持久化磁碟後,再給生產者傳送一個Ack訊號。
消費者丟資料:與生產者基本一直,等消費完成並接收到confirm才能確認是消費成功。超時或者失敗則重試,重試超過指定閾值的時候,計入死信佇列並獨立處理。