プロンプトとコンテキスト
トラフィックのスパイク後、ある API が 429 Too Many Requests を返しました。このステータスコードの責任境界、Retry-After の読み取り方、どのリクエストがリトライ可能か、そしてクライアントが過負荷を連鎖障害へと発展させないようにする方法を説明してください。
面接官が評価するポイント
- 429 を恒久的なサーバー障害ではなく、レート制限シグナルとして理解しているか。
- Retry-After の両方のフォーマットおよびヘッダーが存在しないケースを正しく処理できるか。
- リトライを決定する際に、べき等性、デッドライン、ビジネス上の副作用を組み合わせているか。
- 指数バックオフ、ジッター、バジェット、レート制御によってサービスを保護できるか。
回答前に確認すべき質問
- 制限はユーザー、トークン、テナント、IP、または共有リソースのいずれごとですか?
- レスポンスに Retry-After が含まれており、クライアントはその時計を信頼できますか?
- メソッドおよびビジネス操作はべき等ですか、それともべき等性キーが存在しますか?
- 全体のデッドライン、リトライ上限、リトライバジェットは設定されていますか?
- サービスはクォータ、残りキャパシティ、またはリクエスト ID を公開していますか?
30秒の回答フレームワーク
私は 429 をレート制限のフィードバックとして扱い、秒数または HTTP 日付形式である Retry-After を読み取ります。クライアント側の安全なバックオフ上限内でサーバーの指示を尊重し、ジッターを追加します。べき等な操作、またはべき等性キーによって保護された操作のみを、デッドライン、試行回数、バジェットの制限内で自動リトライします。Retry-After がない場合はジッター付き指数バックオフを使用し、429 が連続する場合はリトライを停止して呼び出し元に制御を戻します。
ステップごとの詳細解説
ステップ 1: 429 セマンティクスを確認する
RFC 6585 は、一定期間内のリクエストが多すぎる場合に対して 429 を定義し、Retry-After の使用を許可しています。これはクライアントにレートを下げるよう指示するものであり、500 のように扱って即座にリトライすべきではありません。
ステップ 2: Retry-After をパースする
Retry-After は、非負の整数秒または HTTP 日付のいずれかになります。日付の場合は、レスポンスの Date または信頼できる時計を使用して遅延を見積もり、負の値、極端に大きな値、不正な形式の値を制限します。
Retry-After: 8
Retry-After: Wed, 02 Aug 2026 02:00:00 GMTステップ 3: リプレイが安全かどうかを判断する
GET や HEAD などの安全なメソッドは通常リトライ可能です。書き込みには、べき等セマンティクス、べき等性キー、またはサーバー側の重複排除が必要です。同じメソッドであっても、課金、メール送信、タスク作成などの副作用を持つ場合があります。
ステップ 4: 遅延とバックオフを計算する
まず Retry-After を尊重し、次にクライアントの指数バックオフ上限とランダムジッターを適用します。ジッターは、多数のクライアントが同一瞬間に一斉にリトライするのを防ぎます。待機時間は、リクエストのデッドラインを無制限に延長するのではなく、その枠内に収める必要があります。
ステップ 5: リトライの増幅を制限する
リクエストごとの試行回数、グローバルなリトライバジェット、同時実行数の上限を設定します。429 を返し続けるリソースに対してはレートを下げ、リトライが通常のトラフィックキャパシティを消費しないよう、必要に応じてローカルキューやサーキットブレーカーを使用します。
ステップ 6: クライアントとサーバーの責任を分離する
サーバーは明示的な制限シグナルと可測なフィールドを提供します。クライアントはそのシグナルを尊重し、バックオフして停止します。復旧後は、待機中のすべてのリクエストを一斉に解放するのではなく、徐々にトラフィックを増加させます。
ステップ 7: 結果を記録して改善する
429 の発生率、Retry-After の分布、最終成功率、リトライ回数、デッドラインによる破棄を追跡します。429 を単一リクエストの失敗として扱うのではなく、そのデータをクォータ、クライアントバジェット、アラートの調整に活用します。
高品質な回答サンプル
私ならまず、制限の適用単位とレスポンスヘッダーを確認します。Retry-After: 8 の場合、クライアントは少なくとも 8 秒待機します。HTTP 日付の場合は、信頼できる時計と最大上限値を使用して遅延を計算します。べき等性キーを持つ注文照会は自動リトライできますが、重複排除のない課金作成はビジネスレイヤーで確認する必要があります。ランダムジッター付きの指数バックオフ、リクエストあたり最大 3 回の試行上限、グローバルなリトライバジェット、および全体のデッドラインを使用します。429 が継続する場合は、リトライが過負荷を増幅させないよう、同時実行数を減らしてキューを一時停止します。メトリクスとしては、クォータやアラート調整のために 429 発生率、待機時間、最終成功率を監視します。
よくある間違い
- 429 を 500 と同様に扱い、密なループで即座にリトライする。
- 整数形式の Retry-After のみをサポートし、HTTP 日付形式を無視する。
- べき等な読み取りと副作用を伴う書き込みを区別しない。
- デッドライン、バジェット、同時実行制限を省略し、リトライが無制限に増加する。
- すべてのクライアントに同一の固定遅延を設定し、同期されたリトライスパイクを発生させる。
追加の質問と回答
追加質問 1: Retry-After がない場合、どのくらい待機すべきですか?
最大遅延、試行回数、合計デッドラインの制限を設けたジッター付き指数バックオフを使用します。単一の固定値を選択するのではなく、429 の発生率やクォータに基づいて調整します。
追加質問 2: HTTP 日付が過去の場合はどうしますか?
サーバー側の遅延をゼロとして扱いますが、ローカルバックオフとジッターは引き続き適用し、時計のズレやサーバー側の生成問題を記録します。日付が無効だからといって高並行リトライを一斉に実行してはいけません。
追加質問 3: POST はリトライできますか?
API がべき等性を定義している場合、べき等性キーを提供している場合、またはビジネスレイヤーで重複排除が可能な場合に限られます。それ以外の場合は、明示的な再送信の判断を呼び出し元に委ねます。
追加質問 4: 多数のインスタンスが 1 つのクォータを共有している場合はどうなりますか?
プロセス間またはテナントスコープでリトライバジェットとレート制御を調整し、共有シグナルを使用して同時実行数を削減します。インスタンスごとのバックオフだけでは全体の超過を防ぐことはできません。
追加質問 5: 復旧時の新たな過負荷スパイクをどのように防ぎますか?
キューを段階的に流し、ジッターと同時実行上限を維持し、429 の発生率とレイテンシを観察した後にのみレートを引き上げます。待機中のリクエストを一度にすべて解放しないでください。
追加質問 6: この戦略が機能していることを証明するメトリクスは何ですか?
テナントやリソースごとにセグメント化された 429 発生率、リトライ増幅率、成功率、P95 レイテンシ、最終破棄数、復旧時間を比較します。