コンシューマーが例外を検出した場合、ApsaraMQ for RocketMQ は消費リトライポリシーに基づいてメッセージを再配信し、障害回復を可能にします。このトピックでは、メッセージ消費リトライ機能の利用シーン、原則、バージョンの互換性、および推奨事項について説明します。
利用シーン
ApsaraMQ for RocketMQ のメッセージ消費リトライ機能は、主にビジネスロジックの失敗によって引き起こされる消費の完全性の問題に対処します。この機能はビジネスのフォールバック戦略であり、ビジネスのフロー制御に使用するべきではありません。
-
以下のシナリオでメッセージリトライを使用することを推奨します。
-
現在のメッセージ内容に関連する理由でビジネス処理が失敗する場合。たとえば、メッセージのトランザクション解決がまだ利用できないが、短時間で成功すると予想される場合などです。
-
消費失敗の原因が永続的でない場合。つまり、失敗は現在のメッセージにとって低確率のイベントであり、定期的に発生するものではありません。後続のメッセージは正常に消費される可能性が高いです。この場合、現在のメッセージの消費をリトライして、プロセスがブロックされるのを回避できます。
-
-
以下のシナリオではメッセージリトライの使用は推奨されません。
-
処理ロジックで条件分岐のために消費失敗を使用することは推奨されません。これは、処理ロジックがこの分岐が頻繁に実行されることをすでに予測しているためです。
-
処理ロジックでレート制限のために消費失敗を使用することは推奨されません。レート制限の目的は、ピークシェービングのために超過したメッセージを一時的にキューにスタックすることであり、リトライプロセスに送信することではありません。
-
目的
ミドルウェアによる非同期デカップリングにおける典型的な問題は、ダウンストリームサービスがメッセージイベントの処理に失敗した場合に、呼び出しチェーン全体の完全性を確保することです。金融グレードで信頼性の高いビジネスメッセージングミドルウェアとして、ApsaraMQ for RocketMQ は信頼性の高い伝送ポリシーで設計されています。包括的な確認応答とリトライメカニズムを使用して、すべてのメッセージがビジネスの期待どおりに処理されることを保証します。
ApsaraMQ for RocketMQ のメッセージ確認応答メカニズムと消費リトライポリシーを理解することは、以下の問題に対処するのに役立ちます。
-
ビジネスのために完全なメッセージ処理を保証する方法:消費リトライポリシーを理解することは、コンシューマーロジックを設計および実装する際に、各メッセージの完全性を確保するのに役立ちます。この実践により、例外発生時にメッセージが無視され、ビジネスの状態が不整合になるのを防ぎます。
-
システム例外中に処理中のメッセージの状態を回復する方法:これにより、故障などのシステム例外が発生したときに処理中のメッセージの状態を回復する方法、および状態の不整合が発生するかどうかを理解するのに役立ちます。
消費リトライポリシー
消費リトライポリシーは、コンシューマーがメッセージの消費に失敗した後の、メッセージのリトライ間隔と最大リトライ回数を定義します。
メッセージリトライのトリガー
-
消費の失敗。これには、コンシューマーが失敗ステータスを返すか、予期しない例外をスローするケースが含まれます。
-
メッセージ処理のタイムアウト。これには、PushConsumer でのキューイングタイムアウトが含まれます。
メッセージリトライの主な動作
-
リトライプロセスのステートマシン:リトライプロセス中のメッセージの状態と遷移ロジックを制御します。
-
リトライ間隔:最後の消費失敗またはタイムアウトから、メッセージが再び消費可能になるまでの時間です。
-
最大リトライ回数:メッセージをリトライできる最大回数です。
リトライポリシーの違い
メッセージリトライポリシーの内部メカニズムと設定方法は、コンシューマータイプによって異なります。次の表にその違いを示します。
|
コンシューマータイプ |
リトライプロセスのステートマシン |
リトライ間隔 |
最大リトライ回数 |
|
PushConsumer |
|
作成時のコンシューマーグループのメタデータによって制御されます。
|
コンソールまたは OpenAPI 操作で設定します。 |
|
SimpleConsumer |
|
メッセージ受信時に不可視期間を変更する API 操作を使用して変更します。 |
コンソールまたは OpenAPI 操作で設定します。 |
特定のリトライポリシーの詳細については、「PushConsumer の消費リトライポリシー」および「SimpleConsumer の消費リトライポリシー」をご参照ください。
PushConsumer の消費リトライポリシー
リトライステートマシン
PushConsumer がメッセージを消費すると、メッセージは次の主要な状態を経由します:
-
Ready:リソースが使用可能な状態です。
メッセージは ApsaraMQ for RocketMQ サーバー上で準備ができており、コンシューマーによって消費されることができます。
-
Inflight:処理が進行中であることを示します。
メッセージはコンシューマークライアントによって受信され、処理中です。消費結果はまだ返されていません。
-
WaitingRetry:これは PushConsumer 固有の状態です。
メッセージ処理が失敗またはタイムアウトすると、消費リトライロジックがトリガーされます。現在のリトライ回数が最大値に達していない場合、メッセージは WaitingRetry 状態に入ります。リトライ間隔が経過すると、メッセージは Ready 状態に戻り、再び消費可能になります。リトライ間の間隔は、頻繁で無効な失敗を防ぐために延長されることがあります。
-
Commit:コミットの状態です。
これは正常な消費の状態です。コンシューマーは成功応答を返し、メッセージのステートマシンを終了させます。
-
DLQ:デッドレター状態です。
これは消費ロジックの最終的なフォールバックメカニズムです。メッセージが最大リトライ回数を超えても消費に失敗し、デッドレターメッセージ機能が有効になっている場合、失敗したメッセージはデッドレタートピックに配信されます。その後、デッドレタートピックからメッセージを消費してビジネスリカバリーを実行できます。詳細については、「デッドレターメッセージ」をご参照ください。
-
Discard:削除または除去します。
メッセージが最大リトライ回数を超えても消費に失敗し、デッドレターメッセージ機能が無効になっている場合、失敗したメッセージは破棄されます。

たとえば、上の図はメッセージのリトライプロセスを示しています。メッセージが Ready 状態で 5 秒間留まり、処理時間が 6 秒であると仮定します。
メッセージがリトライされるたびに、その状態は Ready から Inflight、そして WaitingRetry に変わります。リトライ間隔は、最後の消費失敗またはタイムアウトから、メッセージが再び消費可能になるまでの時間です。2 つの消費試行間の実際の時間には、処理時間と Ready 状態での滞在時間も含まれます。例:
-
メッセージは最初の消費試行のために 0 秒で Ready 状態に入ります。
-
コンシューマーの処理速度のため、メッセージは 5 秒経過するまで消費のためにプルされません。6 秒の処理後、例外が発生し、クライアントは消費失敗を返します。
-
メッセージはすぐにリトライできません。再び消費される前に、リトライ間隔が経過するのを待つ必要があります。
-
21 秒で、メッセージは Ready 状態に戻ります。
-
さらに 5 秒後、クライアントは再びメッセージの消費を開始します。
したがって、2 つの消費試行間の実際の時間間隔は、処理時間 + リトライ間隔 + Ready 状態での滞在時間 = 21 秒となります。
リトライ間隔
-
順序なしメッセージ (非順序メッセージ):リトライ間隔は段階的なスケジュールを使用します。次の表に具体的な間隔を示します。
再試行
リトライ間隔
再試行
リトライ間隔
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。
最大制限:1,000。
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 による順序メッセージの消費リトライは、コンシューマークライアント上で発生します。サーバーは消費リトライの詳細なログを取得できません。メッセージトレース内の順序メッセージの配信結果が「failed」の場合、最大リトライ回数やコンシューマークライアントなどの情報についてコンシューマークライアントのログを確認してください。
コンシューマークライアントのログパスの詳細については、「ログ設定」をご参照ください。
クライアントログで以下のキーワードを検索すると、消費失敗に関連する内容をすばやく見つけることができます:
Message listener raised an exception while consuming messages
Failed to consume fifo message finally, run out of attempt times
SimpleConsumer の消費リトライポリシー
リトライステートマシン
SimpleConsumer がメッセージを消費すると、メッセージは次の主要な状態を経由します:
-
Ready:リソースが使用可能な状態です。
メッセージは ApsaraMQ for RocketMQ サーバー上で準備ができており、コンシューマーによって消費されることができます。
-
Inflight:処理が進行中であることを示します。
メッセージはコンシューマークライアントによって受信され、処理中です。消費結果はまだ返されていません。
-
Commit:コミットの状態です。
これは正常な消費の状態です。コンシューマーは成功応答を返し、メッセージのステートマシンを終了させます。
-
DLQ:デッドレター状態です。
これは消費ロジックの最終的なフォールバックメカニズムです。メッセージが最大リトライ回数を超えても消費に失敗し、デッドレターメッセージ機能が有効になっている場合、失敗したメッセージはデッドレタートピックに配信されます。その後、デッドレタートピックからメッセージを消費してビジネスリカバリーを実行できます。詳細については、「デッドレターメッセージ」をご参照ください。
-
Discard:削除または除去します。
メッセージが最大リトライ回数を超えても消費に失敗し、デッドレターメッセージ機能が無効になっている場合、失敗したメッセージは破棄されます。
PushConsumer のリトライポリシーとは異なり、SimpleConsumer のリトライ間隔は事前に割り当てられます。メッセージを受信するたびに、コンシューマーは API を呼び出す際に不可視期間パラメーター InvisibleDuration を設定します。この期間は、メッセージの最大処理時間です。消費失敗がリトライをトリガーした場合、不可視期間パラメーターの値が再利用されるため、次のリトライ間隔を設定する必要はありません。

不可視期間は事前に割り当てられるため、ビジネスにおける実際のメッセージ処理時間と大きく異なる場合があります。API 操作を使用して不可視期間を変更できます。
たとえば、最大処理時間を 20 ms に設定したが、メッセージがその時間内に処理できない場合、メッセージの不可視期間を変更して処理時間を延長できます。これにより、メッセージがリトライメカニズムをトリガーするのを防ぎます。
メッセージの不可視期間を変更するには、次の条件を満たす必要があります:
-
メッセージ処理がタイムアウトしていない。
-
メッセージの消費ステータスがコミットされていない。
次の図に示すように、不可視期間の変更はすぐに有効になります。不可視期間は、API が呼び出された瞬間から再計算されます。

メッセージのリトライ間隔
メッセージのリトライ間隔 = 不可視期間 - 実際のメッセージ処理時間
SimpleConsumer の消費リトライ間隔は、メッセージの不可視期間によって制御されます。たとえば、不可視期間が 30 ms で、メッセージ処理に 10 ms かかって失敗応答が返された場合、次のリトライは 20 ms 後に発生します。この場合、メッセージのリトライ間隔は 20 ms です。メッセージが処理されず、30 ms 後に結果が返されない場合、メッセージはタイムアウトし、すぐにリトライされます。この場合、リトライ間隔は 0 ms です。
最大リトライ回数
デフォルト値:16。
最大制限:1,000。
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
-
UpdateConsumerGroup OpenAPI 操作を呼び出します。
-
コンソールで変更します:
次の手順で操作を実行できます:
-
インスタンス数 ページで、対象のインスタンスの名前をクリックします。
-
左側のナビゲーションウィンドウで、グループ をクリックします。グループ ページで、グループの作成 をクリックします。

-
Remoting SDK
-
Remoting SDK パラメーターを使用して変更:コンシューマーの `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 分です。