全部產品
Search
文件中心

ApsaraMQ for RocketMQ:消費重試

更新時間:Jan 26, 2026

消費者出現異常,雲訊息佇列 RocketMQ 版會根據消費重試策略重新投遞該訊息進行故障恢複。本文介紹消費重試的應用情境、原理機制、版本相容性和使用建議。

應用情境

雲訊息佇列 RocketMQ 版的消費重試主要解決的是業務處理邏輯失敗導致的消費完整性問題,是一種為業務兜底的策略,不應該被用作商務程序控制。

  • 以下情境建議使用訊息重試

    • 業務處理失敗,且失敗原因跟當前的訊息內容相關,比如該訊息對應的事務狀態還未擷取到,預期一段時間後可執行成功。

    • 消費失敗的原因不會導致連續性,即當前訊息消費失敗是一個小機率事件,不是常態化的失敗,後面的訊息大機率會消費成功。此時可以對當前訊息進行重試,避免進程阻塞。

  • 以下情境不建議使用訊息重試

    • 消費處理邏輯中使用消費失敗來做條件判斷的結果分流,是不合理的,因為處理邏輯已經預見到一定會大量出現該判斷分支。

    • 消費處理中使用消費失敗來做處理速率限流,是不合理的。限流的目的是將超出流量的訊息暫時堆積在隊列中,以達到削峰的作用,而不是讓訊息進入重試鏈路。

應用目的

訊息中介軟體在進行非同步解耦時的一個典型問題是如果下遊服務處理訊息事件失敗,如何保證整個調用鏈路的完整性。雲訊息佇列 RocketMQ 版作為金融級的可靠業務訊息中介軟體,在訊息投遞處理機制的設計上天然支援可靠傳輸策略,通過完整的確認和重試機制保證每條訊息都按照業務的預期被處理。

瞭解雲訊息佇列 RocketMQ 版的訊息確認機制以及消費重試策略可以協助您分析如下問題:

  • 如何保證業務完整處理訊息:瞭解消費重試策略,可以在設計實現消費者邏輯時保證每條訊息處理的完整性,避免部分訊息出現異常時被忽略,導致業務狀態不一致。

  • 系統異常時處理中的訊息狀態如何恢複:協助您瞭解當系統出現異常(宕機故障)等情境時,處理中的訊息狀態如何恢複,是否會出現狀態不一致。

消費重試策略

消費重試策略指消費者在消費某條訊息失敗後,訊息重試的間隔時間和最大重試次數。

訊息重試的觸發條件

  • 消費失敗,包括消費者返回訊息失敗狀態標識或拋出非預期異常。

  • 訊息處理逾時,包括在PushConsumer中排隊逾時。

訊息重試主要行為

  • 重試過程狀態機器:控制訊息在重試流程中的狀態和變化邏輯。

  • 稍候再試:上一次消費失敗或逾時後,距下次訊息可被重新消費的間隔時間。

  • 最大重試次數:訊息可被重試消費的最大次數。

訊息重試策略差異

根據消費者類型不同,訊息重試策略的具體內部機制和設定方法有所不同,具體差異如下:

消費者類型

重試過程狀態機器

稍候再試

最大重試次數

PushConsumer

  • 已就緒

  • 處理中

  • 待重試

  • 提交

  • 死信

  • 丟棄

消費者分組建立時中繼資料控制。

  • 無序訊息:階梯間隔

  • 順序訊息:固定間隔時間

通過控制台或OpenAPI設定

修改最大重試次數

SimpleConsumer

  • 已就緒

  • 處理中

  • 提交

  • 死信

  • 丟棄

通過API修改擷取訊息時的不可見時間。

通過控制台或OpenAPI設定

修改最大重試次數

具體的重試策略,請參見下文PushConsumer消費重試策略SimpleConsumer消費重試策略

PushConsumer消費重試策略

重試狀態機器

PushConsumer消費訊息時,訊息的幾個主要狀態如下:Push消費狀態機器

  • Ready:已就緒狀態。

    訊息在雲訊息佇列 RocketMQ 版服務端已就緒,可以被消費者消費。

  • Inflight:處理中狀態。

    訊息被消費者用戶端擷取,處於消費中還未返回消費結果的狀態。

  • WaitingRetry:待重試狀態,PushConsumer專屬的狀態。

    當消費者訊息處理失敗或消費逾時,會觸發消費重試邏輯判斷。如果當前重試次數未達到最大次數,則該訊息變為待重試狀態,經過稍候再試後,訊息將重新變為已就緒狀態可被重新消費。多次重試之間,可通過稍候再試進行延長,防止無效高頻的失敗。

  • Commit:提交狀態。

    消費成功的狀態,消費者返回成功響應即可結束訊息的狀態機器。

  • DLQ:死信狀態。

    消費邏輯的最終兜底機制,訊息重試失敗且超過最大重試次數,若儲存死信訊息功能開啟,該失敗訊息會被投遞至死信Topic。您可以通過消費死信Topic的訊息進行業務恢複。具體資訊,請參見死信訊息

  • Discard:丟棄。

    訊息重試失敗且超過最大重試次數,若儲存死信訊息功能未開啟,該失敗訊息會被直接丟棄。

訊息間隔時間

舉例:某條訊息的消費重試流程如上圖所示,假設訊息處於已就緒狀態的時間長度為5 s,消費耗時為6 s。

每次重試訊息狀態都會經過已就緒->處理中->待重試的變化,訊息的稍候再試指的是上一次消費失敗或逾時後,距下次訊息可被重新消費的間隔時間。實際訊息兩次消費之間的間隔時間還包括消費耗時和已就緒狀態的期間。例如:

  • 訊息第一次消費時第0 s進入已就緒狀態。

  • 受消費者處理速度的影響,到第5 s時才開始拉取訊息消費,6 s後訊息處理異常用戶端返回消費失敗。

  • 此時還不能進行消費重試,需要等待稍候再試後才能開始再次消費。

  • 等到第21 s時訊息再次變為已就緒狀態。

  • 5 s後用戶端才再次開始重新消費訊息。

因此,實際訊息兩次消費的間隔時間為:消費耗時+稍候再試+已就緒的期間=21 s。

稍候再試時間

  • 無序訊息(非順序訊息):稍候再試為階梯時間,具體時間如下:

    第幾次重試

    稍候再試時間

    第幾次重試

    稍候再試時間

    1

    10秒

    9

    7分鐘

    2

    30秒

    10

    8分鐘

    3

    1分鐘

    11

    9分鐘

    4

    2分鐘

    12

    10分鐘

    5

    3分鐘

    13

    20分鐘

    6

    4分鐘

    14

    30分鐘

    7

    5分鐘

    15

    1小時

    8

    6分鐘

    16

    2小時

    說明

    若重試次數超過16次,後面每次稍候再試都為2小時。

  • 順序訊息:稍候再試為固定時間,具體取值,請參見參數限制

最大重試次數

  • 預設值:16次。

  • 最大限制:不超過1000次。

PushConsumer的最大重試次數由消費者分組的中繼資料控制,修改方式,請參見修改最大重試次數

例如,最大重試次數為3次,則該訊息最多可被投遞4次,1次為原始訊息,3次為重試投遞次數。

使用樣本

PushConsumer觸發訊息重試只需要返回消費失敗的狀態代碼即可,當出現非預期的異常時,也會被SDK捕獲。

SimpleConsumer simpleConsumer = null;
        //消費樣本:使用PushConsumer消費普通訊息,如果消費失敗返回錯誤,即可觸發重試。
        MessageListener messageListener = new MessageListener() {
            @Override
            public ConsumeResult consume(MessageView messageView) {
                System.out.println(messageView);
                //返回消費失敗,會自動重試,直至到達最大重試次數。
                return ConsumeResult.FAILURE;
            }
        };
            

查看消費重試日誌

PushConsumer順序消費的重試是在消費者用戶端進行,服務端無法擷取消費重試的詳細日誌,若訊息軌跡中順序訊息的投遞結果為失敗時,您需要在消費者用戶端日誌中查看訊息重試的最大次數、消費者用戶端等資訊。

消費者用戶端日誌查看路徑,請參見日誌配置

您可以通過搜尋以下關鍵字在用戶端日誌中快速定位消費失敗的相關內容:

Message listener raised an exception while consuming messages
Failed to consume fifo message finally, run out of attempt times

SimpleConsumer消費重試策略

重試狀態機器

SimpleConsumer消費訊息時,訊息的幾個主要狀態如下:PushConsumer狀態機器

  • Ready:已就緒狀態。

    訊息在雲訊息佇列 RocketMQ 版服務端已就緒,可以被消費者消費。

  • Inflight:處理中狀態。

    訊息被消費者用戶端擷取,處於消費中還未返回消費結果的狀態。

  • Commit:提交狀態。

    消費成功的狀態,消費者返回成功響應即可結束訊息的狀態機器。

  • DLQ:死信狀態。

    消費邏輯的最終兜底機制,訊息重試失敗且超過最大重試次數,若儲存死信訊息功能開啟,該失敗訊息會被投遞至死信Topic。您可以通過消費死信Topic的訊息進行業務恢複。具體資訊,請參見死信訊息

  • Discard:丟棄。

    訊息重試失敗且超過最大重試次數,若儲存死信訊息功能未開啟,該失敗訊息會被直接丟棄。

和PushConsumer消費重試策略不同的是,SimpleConsumer消費者的稍候再試是預分配的,每次擷取訊息,消費者會在調用API時設定一個不可見時間參數InvisibleDuration,即訊息的最大處理時間長度。若訊息消費失敗觸發重試,不需要設定下一次重試的時間間隔,直接複用不可見時間參數的取值。

simpleconsumer重試

由於不可見時間為預分配的,可能和實際業務中的訊息處理時間差別較大,您可以通過API介面修改不可見時間。

例如,您預設訊息處理耗時最多20 ms,但實際業務中20 ms內訊息處理不完,您可以修改訊息不可見時間,延長訊息處理時間,避免訊息觸發重試機制。

修改訊息不可見時間需要滿足以下條件:

  • 訊息處理未逾時

  • 訊息處理未提交消費狀態

如下圖所示,訊息不可見時間修改後立即生效,即從調用API時刻開始,重新計算訊息不可見時間。

修改不可見時間

訊息稍候再試

訊息稍候再試=不可見時間-訊息實際處理時間長度

SimpleConsumer的消費稍候再試通過訊息的不可見時間控制。例如,訊息不可見時間為30 ms,實際訊息處理用了10 ms就返回失敗響應,則距下次訊息重試還需要20 ms,此時的訊息稍候再試即為20 ms;若直到30 ms訊息還未處理完成且未返回結果,則訊息逾時,立即重試,此時稍候再試即為0 ms。

最大重試次數

  • 預設值:16次。

  • 最大限制:不超過1000次。

SimpleConsumer的最大重試次數由消費者分組建立的中繼資料控制,修改方式,請參見修改最大重試次數

例如,最大重試次數為3次,則該訊息最多可被投遞4次,1次為原始訊息,3次為重試投遞次數。

使用樣本

SimpleConsumer觸發訊息重試只需要等待即可。

 //消費樣本:使用SimpleConsumer消費普通訊息,如果希望重試,只需要靜默等待逾時即可,服務端會自動重試。
        List<MessageView> messageViewList = null;
        try {
            messageViewList = simpleConsumer.receive(10, Duration.ofSeconds(30));
            messageViewList.forEach(messageView -> {
                System.out.println(messageView);
                //如果處理失敗,希望服務端重試,只需要忽略即可,等待訊息再次可見後即可重試擷取。
            });
        } catch (ClientException e) {
            //如果遇到系統流控等原因造成拉取失敗,需要重新發起擷取訊息請求。
            e.printStackTrace();
        }

修改最大重試次數

您可以通過以下方式修改PushConsumer和SimpleConsumer的訊息消費的最大重試次數。

重要

1. 如您的用戶端使用 Remoting 協議,實際最大重試次數將以用戶端中的設定為準,此處的配置不會生效。如用戶端使用 gRPC 協議,最大重試次數將遵循此處配置。

2. 消費重試策略(階梯退避、固定間隔),僅對使用 gRPC 協議的用戶端生效,對使用 Remoting 協議的用戶端無效。

gRPC SDK

  • 通過OpenAPI方式修改:更新消費者分組

  • 通過控制台方式修改:

    操作入口如下:

    1. 執行個體列表頁面中單擊目標執行個體名稱。

    2. 在左側導覽列單擊Group 管理,然後在Group 管理頁面單擊创建 Group

    訊息重試策略

Remoting SDK

  • 通過 Remoting SDK 參數修改:修改consumer的 maxReconsumeTimes 屬性值。

使用建議

合理重試,避免因限流等訴求觸發消費重試

上文應用情境中提到,訊息重試適用業務處理失敗且當前消費為小機率事件的情境,不適合在連續性失敗的情境下使用,例如消費限流情境。

  • 錯誤樣本:

    如果當前消費速度過高觸發限流,則返回消費失敗,等待下次重新消費。

  • 正確樣本:

    如果當前消費速度過高觸發限流,則延遲擷取訊息,稍後再消費。

訊息重試常見問題

訊息消費逾時時間如何設定?

消費逾時時間由消費者用戶端設定,具體參數設定如下:

gRPC協議

  • SimpleConsumer:逾時時間最大可設定12小時;最小設定為10秒。

    程式碼範例如下:

    private long minInvisiableTimeMillsForRecv = Duration.ofSeconds(10).toMillis();
    private long maxInvisiableTimeMills = Duration.ofHours(12).toMillis();
  • PushConsumer:預設230分鐘,不支援修改。

Remoting協議

consumer.setConsumeTimeout(15); //參數單位:分鐘,最小1分鐘,最大180分鐘