プロデューサーが ApsaraMQ for RocketMQ ブローカーにメッセージを送信する際、ネットワークの問題、ブローカーの再起動、または容量制限によりリクエストが失敗することがあります。クライアント SDK は、以下の 2 つの組み込みメカニズムによってこれらの障害を処理します。
送信リトライ:失敗したメッセージが成功するか、リトライの上限に達するまで自動的に再送信します。
スロットリング:容量が不足している場合にリクエストを拒否することで、ブローカーを過負荷から保護します。
両方のメカニズムは連携して動作します。スロットリングによってリクエストが拒否されると、リトライメカニズムは指数バックオフを使用して、ブローカーにさらなる負荷をかけることなくメッセージを再送信します。
送信リトライ
リトライプロセス
クライアント SDK には、組み込みのリトライロジックが含まれています。送信リクエストが失敗すると、SDK は自動的にメッセージを再送信します。アプリケーションレベルでのリトライコードは不要です。
プロデューサーを初期化する際に、最大リトライ回数を設定します。リクエストが失敗した場合、SDK はメッセージが配信されるか、リトライの上限に達するまでリトライを続けます。最後のリトライが失敗した後、SDK はアプリケーションにエラーを返します。
リトライの動作は送信モードによって異なります。
| 送信モード | スレッドの動作 | 最終的な失敗時 |
|---|---|---|
| 同期 | 呼び出し元のスレッドは、リトライシーケンス全体でブロックされます | SDK が例外をスローします |
| 非同期 | 呼び出し元のスレッドはブロックされません | SDK が失敗のコールバックイベントを配信します |
リトライのトリガー
リトライは、次の 2 種類の障害によってトリガーされます。
クライアント側の障害
ネットワーク例外による接続障害またはリクエストタイムアウト。
ブローカーの再起動またはアンデプロイによる接続障害。
ブローカーの動作が遅いことによるリクエストタイムアウト。
ブローカー側のエラー
システムロジックエラー:ブローカーでの内部処理エラー。
システムスロットリングエラー:ブローカーが容量を超えたため、リクエストを拒否します。詳細については、「スロットリング」をご参照ください。
トランザクションメッセージは、透明なリトライのみをサポートします。SDK は、ネットワーク例外やタイムアウト時にトランザクションメッセージをリトライしません。
再試行間隔
再試行間隔はエラーの種類によって異なります。
| エラーの種類 | 再試行間隔 |
|---|---|
| スロットリングを除くすべてのエラー | 即時 (遅延なし) |
| システムスロットリングエラー | ジッター付き指数バックオフ |
スロットリングエラーの場合、SDK は次のパラメーターで指数バックオフを使用します。
| パラメーター | 説明 | デフォルト |
|---|---|---|
INITIAL_BACKOFF | 最初のリトライまでの遅延 | 1 秒 |
MULTIPLIER | リトライごとに遅延が増加する係数 | 1.6 |
JITTER | 各遅延に適用されるランダム化係数 | 0.2 |
MAX_BACKOFF | リトライ間の最大遅延 | 120 秒 |
MIN_CONNECT_TIMEOUT | 最小接続タイムアウト | 20 秒 |
バックオフアルゴリズムは次のように動作します。
ConnectWithBackoff()
current_backoff = INITIAL_BACKOFF
current_deadline = now() + INITIAL_BACKOFF
while (TryConnect(Max(current_deadline, now() + MIN_CONNECT_TIMEOUT)) != SUCCESS)
SleepUntil(current_deadline)
current_backoff = Min(current_backoff * MULTIPLIER, MAX_BACKOFF)
current_deadline = now() + current_backoff +
UniformRandom(-JITTER * current_backoff, JITTER * current_backoff)完全な仕様については、「gRPC connection backoff」をご参照ください。
合計リトライ時間バジェットの理解
SDK が公開するリトライ制御は、最大リトライ回数のみです。同期モードでは、呼び出し元のスレッドはリトライシーケンス全体でブロックされるため、合計ブロック時間はリクエストごとのタイムアウトと最大リトライ回数の関係に依存します。
合計ブロック時間 (最悪の場合) = 最大リトライ回数 x リクエストごとのタイムアウト + バックオフ遅延の合計スロットリング以外のエラー (即時リトライ) の場合、バックオフ遅延はゼロです。
合計ブロック時間 = 最大リトライ回数 x リクエストごとのタイムアウトスロットリングエラーの場合、バックオフ遅延は指数関数的に累積します。例えば、デフォルトのパラメーターで 5 回リトライする場合:
| リトライ | バックオフ遅延 (概算) | 累積遅延 |
|---|---|---|
| 1 | 1 秒 | 1 秒 |
| 2 | 1.6 秒 | 2.6 秒 |
| 3 | 2.56 秒 | 5.16 秒 |
| 4 | 4.1 秒 | 9.26 秒 |
| 5 | 6.55 秒 | 15.81 秒 |
同期モードで呼び出し元のスレッドが長時間ブロックされるのを避けるために、リクエストごとのタイムアウトと最大リトライ回数を合わせて評価してください。
リトライ上限到達後の失敗メッセージの処理
組み込みのリトライ機能は、配信を保証するものではありません。すべてのリトライが失敗した場合、SDK はエラーを返します。アプリケーションでこのエラーをキャッチし、フォールバック戦略を実装してください。
失敗したメッセージをローカルログやデッドレターストアに書き込み、後で再処理できるようにします。
根本原因を調査できるように、モニタリングシステムにアラートを送信します。
リトライによる重複メッセージの処理
送信リクエストがタイムアウトした場合、SDK はブローカーがすでにメッセージを受信して保存したかどうかを判断できません。リトライによってブローカー上で重複が発生する可能性があります。これは、At-least-once (少なくとも 1 回) 配信システムにおける基本的なトレードオフです。
重複を処理するには、コンシューマーがべき等処理を行うように設計してください。
各メッセージに一意のビジネスキー (注文 ID やトランザクション ID など) を割り当てます。
処理する前に、そのキーがすでに処理済みかどうかを確認します。
データベースの制約や重複排除キャッシュを使用して、一意性を強制します。
スロットリング
スロットリングは、クラウドメッセージングシステムにおける通常の運用メカニズムです。システムの容量が不足している場合や、使用量が事前定義されたしきい値を超えた場合、ApsaraMQ for RocketMQ ブローカーは即座にリクエストを拒否し、システムスロットリングエラーを返します。その後、SDK の組み込みリトライロジックが、指数バックオフを使用して拒否されたリクエストを処理します。
スロットリングのトリガー
スロットリングは、以下のシナリオでトリガーされます。
ストレージプレッシャーの急増:コンシューマーグループがキューの最大オフセットから消費を開始した場合。ビジネスの展開などで、コンシューマーグループが特定の時間に消費を開始する必要があるシナリオでは、キューへのストレージプレッシャーが急増します。詳細については、「コンシューマーの進捗管理」をご参照ください。
メッセージの蓄積:コンシューマーが受信メッセージのレートに追いつけない場合、未消費のメッセージがキューに蓄積されます。蓄積がしきい値を超えると、ブローカーは下流システムへのプレッシャーを軽減するためにスロットリングをトリガーします。
クライアントタイプ別のエラーコードとリトライ動作
スロットリングがトリガーされた場合、エラーコードとリトライ動作はクライアントのプロトコルによって異なります。
gRPC クライアント
| 項目 | 値 |
|---|---|
| エラーコード | 530 |
| エラーメッセージのキーワード | TOO_MANY_REQUESTS |
| リトライ動作 | 指数バックオフによる自動リトライ |
Remoting クライアント
| 項目 | 値 |
|---|---|
| エラーコード | 215 |
| エラーメッセージのキーワード | messages flow control |
Remoting クライアントのリトライ動作は SDK のバージョンによって異なります。
| SDK | スロットリング時のリトライ動作 |
|---|---|
| ApsaraMQ for RocketMQ TCP client SDK for Java < 1.9.0.Final | リトライなし |
| ApsaraMQ for RocketMQ TCP client SDK for Java >= 1.9.0.Final | 指数バックオフによる自動リトライ |
| オープンソース Apache RocketMQ SDK (プロデューサー) | リトライなし |
| オープンソース Apache RocketMQ SDK (コンシューマー) | 指数バックオフによる自動リトライ |
ご利用の SDK バージョンがスロットリングエラー時に自動的にリトライしない場合は、アプリケーションコードに指数バックオフを用いたリトライロジックを実装してください。
サポートされているクライアントのバージョンについては、「SDK の互換性」をご参照ください。
スロットリングの防止と対応
トラフィックスパイク前の容量監視
ApsaraMQ for RocketMQ の可観測性機能を使用して、システムの使用量と容量を監視します。ビジネスの展開や予測されるトラフィックスパイクの前に、以下を確認してください。
ご利用のインスタンスに、予測されるトラフィックに対して十分なリソースがあることを確認します。
コンシューマーグループのラグをチェックして、蓄積リスクを特定します。
必要に応じて、インスタンスをスケールアップするか、コンシューマーのスループットを最適化します。
実行時の予期せぬスロットリングへの対応
予期せずスロットリングが発生し、SDK の組み込みリトライで回復できない場合:
スロットリング状態が解消されるまで、リクエストをフォールバックシステムにルーティングします。
スロットリングイベント (gRPC の場合はエラーコード
530/TOO_MANY_REQUESTS、Remoting の場合は215/messages flow controlを探してください) をログに記録し、根本原因の診断に役立てます。