コンシューマーで例外が発生した場合、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);
// ConsumeResult.FAILURE を返して、最大リトライ回数に達するまで自動的にリトライします。
return ConsumeResult.FAILURE;
}
};
消費リトライログの表示
PushConsumer による順序付き消費のリトライは、コンシューマークライアントで発生します。サーバーは、消費リトライの詳細なログを取得できません。メッセージトレース内の順序付きメッセージの配信結果が 'failed' の場合、コンシューマークライアントのログで最大リトライ回数やコンシューマークライアントなどの情報を確認できます。
コンシューマークライアントのログパスについては、「ログ設定」をご参照ください。
クライアントログで次のキーワードを検索すると、消費の失敗に関連するコンテンツをすばやく見つけることができます。
Message listener raised an exception while consuming messages
Failed to consume fifo message finally, run out of attempt timesSimpleConsumer のリトライポリシー
リトライ状態機械
SimpleConsumer がメッセージを消費するときのメッセージの主な状態は次のとおりです。
Ready
メッセージは ApsaraMQ for RocketMQ サーバー上で準備ができており、コンシューマーによって消費可能です。
Inflight: 処理が進行中であることを示すステータス。
メッセージはコンシューマークライアントによって取得され、処理中ですが、消費結果はまだ返されていません。
Commit
消費成功状態。コンシューマーが成功応答を返すと、メッセージの状態機械は終了します。
DLQ: デッドレター状態。
これは消費ロジックの最終的なフォールバックメカニズムです。デッドレターメッセージを保存する機能が有効になっている場合、最大リトライ回数を超えると、失敗したメッセージはデッドレタートピックに配信されます。デッドレタートピックからメッセージを消費して、ビジネスの回復を実行できます。詳細については、「デッドレターメッセージ」をご参照ください。
Discard
デッドレターメッセージを保存する機能が有効になっていない場合、最大リトライ回数を超えると、失敗したメッセージは破棄されます。
PushConsumer のリトライポリシーとは異なり、SimpleConsumer の再試行間隔は事前に割り当てられます。メッセージを受信するたびに、コンシューマーは API を呼び出すときに不可視期間パラメーター InvisibleDuration を設定します。このパラメーターは、メッセージの最大処理時間を指定します。消費が失敗してリトライがトリガーされた場合、不可視期間パラメーターの値が再利用されるため、次の再試行間隔を設定する必要はありません。

事前に割り当てられた不可視期間は、ビジネスにおける実際のメッセージ処理時間と大幅に異なる場合があります。API 操作を使用して、不可視期間を変更できます。
たとえば、メッセージ処理時間を最大 20 ms に事前設定できます。ただし、実際のビジネスでは、メッセージは 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 プロトコルを使用するクライアントには無効です。
OpenAPI 操作を使用して変更する: UpdateConsumerGroup
コンソールを使用して変更する:
次のステップに従います。
インスタンス数 ページで、対象のインスタンスの名前をクリックします。
左側のナビゲーションウィンドウで、グループ をクリックします。グループ ページで、グループの作成 をクリックします。

使用に関する推奨事項
合理的なリトライとスロットリング目的での消費リトライのトリガー回避
「シナリオ」で述べたように、メッセージリトライは、ビジネス処理が失敗し、現在の消費失敗がまれなイベントであるシナリオに適しています。消費スロットリングなどの永続的な失敗のシナリオには適していません。
不適切な例:
現在の消費速度が速すぎてスロットリングがトリガーされた場合、消費失敗を返して次の再消費を待つことができます。
適切な例:
現在の消費速度が速すぎてスロットリングがトリガーされた場合、メッセージの受信を遅らせて後で消費することができます。
メッセージリトライに関するよくある質問
メッセージ消費タイムアウトの設定方法
消費タイムアウトはコンシューマークライアントで設定されます。具体的なパラメーター設定は次のとおりです。
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。