RocketMQ:死信隊列和消費冪等

1. 死信隊列

上一篇《RocketMQ:消息重試》中我們提到當一條消息消費失敗時,RocketMQ會進行一定次數的重試。重試的結果也很簡單,無非就是在第N次重試時,被成功消費。或者就是經過M次重試後,仍然沒有被消息。這通常是由於消費者在正常情況下無法正確地消費該消息。此時,RocketMQ不會立即將消息丟棄,而是將其發送到該消費者對應的特殊隊列中去。

在RocketMQ中,這種正常情況下無法被消費的消息被稱爲死信消息(Dead-Letter Message),存儲死信消息的特殊隊列稱爲死信隊列(Dead-Letter Queue)。

1.1 死信特性

(1)死信消息具有以下特性:

  • 不會再被消費者正常消費。
  • 有效期與正常消息相同,均爲 3 天,3 天后會被自動刪除。因此,請在死信消息產生後的 3 天內及時處理。

(2)死信隊列具有以下特性:

  • 一個死信隊列對應一個 Group ID, 而不是對應單個消費者實例。
  • 如果一個 Group ID 未產生死信消息,消息隊列 RocketMQ 不會爲其創建相應的死信隊列。
  • 一個死信隊列包含了對應 Group ID 產生的所有死信消息,不論該消息屬於哪個 Topic。

1.2 查看死信消息

(1)在控制條查詢出現死信隊列的主題信息

在這裏插入圖片描述

(2)在消費界面根據主題查詢死信消息

在這裏插入圖片描述

(3)選擇重新發送消息

一條消息進入死信隊列,意味着某些因素導致消費者無法正常消費該消息。因此,通常需要我們對其進行特殊處理。排查可疑因素並解決問題後,可以在消息隊列 RocketMQ 控制檯重新發送該消息,讓消費者重新消費一次。

2. 消息冪等

RocketMQ並不保證一條消息只會被推送一次,因此一條消息就有可能被消費多次。消費者在接收到消息以後,有必要根據業務上的唯一 Key 對消息做冪等處理的必要性。

2.1 消費冪等的必要性

在互聯網應用中,尤其在網絡不穩定的情況下,RocketMQ 的消息有可能會出現重複,這個重複簡單可以概括爲以下情況:

  • 發送時消息重複

    當一條消息已被成功發送到服務端並完成持久化,此時出現了網絡閃斷或者客戶端宕機,導致服務端對客戶端應答失敗。 如果此時生產者意識到消息發送失敗並嘗試再次發送消息,消費者後續會收到兩條內容相同並且 Message ID 也相同的消息。

  • 投遞時消息重複

    消息消費的場景下,消息已投遞到消費者並完成業務處理,當客戶端給服務端反饋應答的時候網絡閃斷。 爲了保證消息至少被消費一次,消息隊列 RocketMQ 的服務端將在網絡恢復後再次嘗試投遞之前已被處理過的消息,消費者後續會收到兩條內容相同並且 Message ID 也相同的消息。

  • 負載均衡時消息重複(包括但不限於網絡抖動、Broker 重啓以及訂閱方應用重啓)

    當RocketMQ 的 Broker 或客戶端重啓、擴容或縮容時,會觸發 Rebalance,此時消費者可能會收到重複消息。

2.2 處理方式

因爲 Message ID 有可能出現衝突(重複)的情況,所以真正安全的冪等處理,不建議以 Message ID 作爲處理依據。 最好的方式是以業務唯一標識作爲冪等處理的關鍵依據,而業務的唯一標識可以通過消息 Key 進行設置:

Message message = new Message();
message.setKey("ORDERID_100");
SendResult sendResult = producer.send(message);

消費方收到消息時可以根據消息的 Key 進行冪等處理:

consumer.subscribe("test", "*", new MessageListener() {
    public Action consume(Message message, ConsumeContext context) {
        String key = message.getKey()
        // 根據業務唯一標識的 key 做冪等處理
    }
});
——End——
更多精彩分享,可掃碼關注微信公衆號哦。

在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章