コンシューマーがメッセージの処理に失敗した場合、または処理がタイムアウトした場合、ApsaraMQ for RocketMQ はリトライポリシーに基づいてメッセージを自動的に再配信します。すべてのリトライ試行が尽きると、メッセージはデッドレターキューに移動されます。デッドレターキュー内のメッセージを消費することで、ビジネスを回復できます。
注意事項
メッセージ ID は、すべてのリトライ試行で変更されません。
消費リトライは、クラスター消費モードでのみ機能します。ブロードキャスト消費モードでは、失敗したメッセージは再配信されません。コンシューマーは次のメッセージにスキップします。
仕組み
メッセージは次の状態を遷移します。
| 状態 | 説明 |
|---|---|
| Ready | メッセージはブローカーにキューイングされ、消費可能です。 |
| Inflight | コンシューマーがメッセージをプルし、処理中です。まだ結果は返されていません。 |
| WaitingRetry | 消費に失敗したか、タイムアウトしました。メッセージは、再試行間隔が経過するまで待機し、Ready 状態に戻ります。 |
| Commit | コンシューマーは成功応答を返しました。消費が完了しました。 |
| DLQ | デッドレターメッセージを保持する機能が有効になっている場合、メッセージはすべてのリトライ試行を使い果たした後、デッドレタートピックに移動されます。 |

リトライのタイミング
2つの連続する消費試行間の間隔には、次の3つのコンポーネントがあります。
試行間の間隔 = 消費時間 + 再試行間隔 + Ready 状態での時間

例えば、メッセージが Ready 状態で5秒間待機し、失敗するまでに処理に6秒かかると仮定します。10秒の再試行間隔の場合:
0 秒 -- メッセージは Ready 状態に入ります。
5 秒 -- コンシューマーがメッセージをプルします (Inflight)。
11 秒 -- 6秒後に消費に失敗します。メッセージは WaitingRetry に入ります。
21 秒 -- 10秒の再試行間隔の後、メッセージは Ready に戻ります。
26 秒 -- コンシューマーは次の試行のためにメッセージを再度プルします。
合計間隔:6 + 10 + 5 = 21 秒。
TCP のリトライポリシー
順序付きメッセージ
| 設定 | 詳細 |
|---|---|
| 再試行間隔 | suspendTimeMillis パラメーターで設定します。有効範囲:10 ~ 30,000 ミリ秒。デフォルト:1,000 ミリ秒 (1 秒)。 |
| 最大リトライ回数 | MaxReconsumeTimes パラメーターで設定します。上限なし。デフォルト:Integer.MAX。 |
順序なしメッセージ
| 設定 | 詳細 |
|---|---|
| 再試行間隔 | 事前定義されたエスカレートするスケジュールに従います (以下の表を参照)。カスタム間隔は順序なしメッセージではサポートされていません。 |
| 最大リトライ回数 | MaxReconsumeTimes パラメーターで設定します。上限なし。デフォルト:16。 |
MaxReconsumeTimes が 16 を超える場合、最初の 16 回のリトライには事前定義されたスケジュールが適用されます。その後のすべてのリトライは、固定の 2 時間間隔を使用します。
順序なしメッセージのリトライ間隔スケジュール
| リトライ | 間隔 | リトライ | 間隔 |
|---|---|---|---|
| 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 時間 |
HTTP のリトライポリシー
HTTP のリトライポリシーは事前定義されており、変更できません。
| メッセージタイプ | 再試行間隔 | 最大リトライ回数 |
|---|---|---|
| 注文済み | 1 分 | 288 |
| 順序なし | 5 分 | 288 |
TCP のリトライ動作の構成
リトライの有効化
クラスター消費モードで消費に失敗したときにリトライをトリガーするには、次のいずれかのアプローチで MessageListener インターフェイスを実装します。
Action.ReconsumeLaterを返す (推奨)nullを返す例外をスローする
public class MessageListenerImpl implements MessageListener {
@Override
public Action consume(Message message, ConsumeContext context) {
// 消費ロジックが例外をスローした場合、メッセージはリトライされます。
doConsumeMessage(message);
// 方法1: Action.ReconsumeLater を返し、メッセージをリトライします。
return Action.ReconsumeLater;
// 方法2: null を返し、メッセージをリトライします。
return null;
// 方法3: 例外をスローし、メッセージをリトライします。
throw new RuntimeException("Consumer Message exception");
}
}リトライの無効化
再配信を防ぐには、消費ロジック内のすべての例外をキャッチし、Action.CommitMessage を返します。
public class MessageListenerImpl implements MessageListener {
@Override
public Action consume(Message message, ConsumeContext context) {
try {
doConsumeMessage(message);
} catch (Throwable e) {
// すべての例外をキャッチし、CommitMessage を返してリトライをスキップします。
return Action.CommitMessage;
}
// 消費に成功しました。
return Action.CommitMessage;
}
}リトライ間隔と最大リトライ回数のカスタマイズ
カスタムリトライ構成には、Java バージョン 1.2.2 以降の TCP クライアント SDK が必要です。詳細については、「リリースノート」をご参照ください。
コンシューマーを開始する前に、コンシューマープロパティで MaxReconsumeTimes と SuspendTimeMillis を設定します。カスタムリトライ間隔は順序付きメッセージにのみ適用されます。順序なしメッセージは常に事前定義されたスケジュールに従います。
Properties properties = new Properties();
// 最大リトライ回数を20に設定します。
properties.put(PropertyKeyConst.MaxReconsumeTimes, "20");
// 再試行間隔を3,000ミリ秒に設定します (順序付きメッセージのみ)。
properties.put(PropertyKeyConst.SuspendTimeMillis, "3000");
Consumer consumer = ONSFactory.createConsumer(properties);同じコンシューマーグループ内のすべてのコンシューマーはリトライ構成を共有します。最も最近開始されたコンシューマーは、以前のコンシューマーの構成を上書きします。グループ内のすべてのコンシューマーが同一の MaxReconsumeTimes および SuspendTimeMillis 値を使用していることを確認してください。
リトライ回数の照会
コンシューマーがメッセージを受信した後、message.getReconsumeTimes() を呼び出して、メッセージが何回リトライされたかを確認します。
public class MessageListenerImpl implements MessageListener {
@Override
public Action consume(Message message, ConsumeContext context) {
// 現在のリトライ回数を取得します。
System.out.println(message.getReconsumeTimes());
return Action.CommitMessage;
}
}ベストプラクティス
デフォルトのリトライ値から始めます。順序なしメッセージのデフォルトスケジュール (16回のリトライで10秒から2時間までエスカレート) は、ほとんどの一時的な障害にうまく機能します。システムの実際の障害パターンを観察した後にのみ調整してください。
デッドレターキューのモニタリングを設定します。すべてのリトライを使い果たしたメッセージはデッドレターキューに移動されます。このキューをモニタリングし、アラートを設定して、失敗したメッセージを迅速に調査し、再処理できるようにしてください。
消費ロジックをべき等に保ちます。リトライ中にメッセージが複数回配信される可能性があるため、重複処理を安全に処理するようにコンシューマーを設計してください。
長時間実行される消費を避けます。処理に時間がかかりすぎると、メッセージがタイムアウトし、不要なリトライをトリガーする可能性があります。長いタスクをより小さなステップに分割するか、消費タイムアウトを増やしてください。