代表的な面接トピック

バックエンド面接:安全なリクエストヘッジングをどのように設計するか?

バックエンド難しい
Offer.cc 編集チーム公開日 更新日

質問

冪等な読み取りAPIにおいて、p50は正常であるもののp99レイテンシが高い状態です。リクエストヘッジングを設計してください:トリガーの閾値、レプリカの選択、キャンセル、負荷保護、可観測性、および無効化するタイミングについて説明してください。

出題とコンテキスト

冪等な読み取りAPIで、p50は健全であるにもかかわらずp99が高くなっています。低速な呼び出しは、突発的なキューイングやホストの一時的な不調に起因していると見られます。リクエストヘッジングを設計してください:プライマリを送信し、一定の遅延後に別のレプリカへコピーを発行し、最初に得られた許容可能な結果を返して、もう一方をキャンセルします。コストと障害増幅の境界について説明してください。

面接官が見ているポイント

目的の理解

ヘッジングはテールレイテンシを対象としており、すべてのリクエストを高速化するわけではありません。安全に再試行可能な読み取りに適しており、副作用のある書き込みを無差別に複製してはなりません。

コストの制御

すべてのリクエストを複製すると、バックエンドの負荷がほぼ2倍になる可能性があります。優れた設計では、遅延トリガー、最大試行回数、スロットリング、キャンセル、および元のリクエストに基づくメトリクスを使用します。

相関障害の処理

過負荷状態にある同一のホストに両方の試行を送信しても意味がほとんどありません。インスタンス、ゾーン、障害ドメインを跨ぐルーティングに加え、キューやエラーの保護がヘッジングの安全性を左右します。

最初に確認すべき質問

  • APIは冪等であり、複数の並行読み取りを受け入れられますか?
  • p50、p95、p99、p99.9のベースラインとSLOはどのような値ですか?
  • 遅い呼び出しは孤立した遅延(stragglers)ですか、それともすべてのレプリカで共有されているキューイングの問題ですか?
  • インスタンス、ゾーン、バージョンを跨いでレプリカはどのように選択されますか?
  • キャンセルによってダウンストリームのスレッド、コネクション、コンピュートリソースは実際に解放されますか?
  • どのようなエラー率、キューの深さ、またはヘッジ発火率でポリシーを無効化しますか?

30秒での回答

「冪等な読み取りに対してのみヘッジングを有効化します。まずプライマリを送信し、リクエストクラスごとに動的なp95相当の閾値を使用します。その閾値が経過し、かつバジェットが許可する場合にのみ、別の障害ドメインにある正常なレプリカへヘッジを1件送信します。1つのデッドラインを共有し、最初の成功結果を返して敗者をキャンセルします。試行回数を制限し、スロットリングとキュー/エラーガードを使用し、p99、発火率、余分なリクエスト数、キャンセルの成功、および元のレイテンシを監視します。負荷が増幅した場合はポリシーを無効化します。」

ステップごとの詳細な回答

リクエストステートマシンの定義

状態は primary_senthedge_waitinghedge_sentwinner_selected、および deadline_exceeded です。まずプライマリを送信します。閾値内に返答があれば終了し、そうでなければヘッジを1件作成します。最初に成功したレスポンスが勝者となり、他のすべての試行にはキャンセルが送られます。

閾値とスコープの選択

メソッド、テナント、リクエストサイズ、またはプロンプト長ごとにバケット分けされたレイテンシヒストグラムを維持します。境界値とコールドスタート用フォールバックを備えた動的なp95相当の閾値を使用します。グローバルな平均値のみに頼ったり、すべてのリクエストを即座に複製したりしてはいけません。

独立したレプリカへのルーティング

プライマリのホスト、ゾーン、または障害ドメインを避けます。キューが短い正常なノードを優先します。すべての候補が過負荷の場合はヘッジングによって混雑が悪化するため、待機、縮退運転、またはフェイルファストを選択します。

キャンセルとデッドラインの処理

クライアントとプロキシはキャンセルトークンを伝播する必要があります。ダウンストリームの処理は停止し、コネクション、スレッド、GPU、キャッシュを解放しなければなりません。重複によってユーザーから見える待ち時間が延びないよう、両方の試行で合計デッドラインを共有します。

ダウンストリームキャパシティの保護

maxAttempts、最小ヘッジ遅延、インフライトバジェット、サービスごとのトークンバケットを設定します。gRPCは maxAttempts を5に制限し、リトライスロットリングを提供します。本番環境の設計では、独自のキャパシティおよびエラーバジェットも必要です。

エラーと非冪等な呼び出しの処理

再試行可能で冪等なケースのみ継続します。決定論的なバリデーションエラーや認証エラーは即座に返します。書き込みには冪等性キーと重複排除が必要であり、あるいは1回のリクエストと補償トランザクションを使用すべきです。

疑似コード

~~~text send(primary) timer = hedgeThreshold(request_class) if primary unfinished at timer and budget_allows(): send(hedge, differentfailuredomain) winner = firstsuccessbefore_deadline() cancel(allotherattempts) record(primarylatency, hedgefired, winner, cancel_result) ~~~

複雑性、可観測性、およびロールバック

最悪の試行回数は maxAttempts によって制限されます。余分なリクエスト量は発火率とキャンセルレイテンシに依存します。p50/p95/p99、ヘッジ発火率、追加QPS、ダウンストリームキュー、エラー、キャンセル成功率、元のプライマリレイテンシを追跡します。混雑やエラーが増加した場合は、サービス、テナント、またはリージョン単位でポリシーを無効化します。

制御目的設定ミスの障害モード
hedge delay遅い呼び出しのみを複製短すぎるとQPSが増幅
maxAttempts並行コピー数を制限高すぎるとリクエストストームが発生
cancellation敗者のリソースを解放失敗するとキャパシティを消費し続ける
throttle budget混雑時に制限を強化メトリクス不足により過負荷が見逃される

模範回答

「まずこれが冪等な読み取りであることを確認し、リクエストクラスごとのレイテンシヒストグラムを構築します。プライマリを送信した後、p95相当の閾値、健全で独立したレプリカ、並行性バジェットのすべてが許可した場合にのみヘッジを1件送信します。両方の試行はデッドラインを共有し、最初の成功が勝者となり、プロキシはキャンセルを伝播しつつリソースが実際に解放されたかを記録します。最大試行回数、トークンスロットリング、キューの深さ、エラー率でバックエンドを保護し、決定論的エラーは決して複製しません。ポリシーをカナリアリリースし、p99、発火率、追加QPS、キャンセルレイテンシ、ヘッジなしのプライマリレイテンシを比較します。ヘッジストームが発生した場合は自動的に無効化します。」

よくある間違い

すべてのリクエストを即座に複製する

これはヘッジングを無条件のレプリケーションに変えてしまい、遅延(stragglers)がテールの原因であるかを確認することなく、通常の負荷とコストを増大させます。

副作用のある書き込みをヘッジする

2つの試行によって2重のレコード作成や2重課金が発生する可能性があります。冪等性キー、重複排除、トランザクションセマンティクスがない場合はヘッジしてはいけません。

同一の障害ドメインを使用する

ホスト、ラック、ゾーンの障害を共有していると両方の試行が遅くなり、過負荷な場所に負荷を追加することになります。

ユーザーから見えるp99のみに着目する

ヘッジングはプライマリパスの悪化を覆い隠し、スケーリングのシグナルを遅らせる可能性があります。ヘッジなしのプライマリレイテンシとキューの深さも記録してください。

キャンセルを無視する

待機を停止することと、ダウンストリームの処理を停止することは異なります。伝播、リソース解放、キャンセルレイテンシを検証してください。

キルスイッチがない

高いエラー率、キューの蓄積、または異常なヘッジ発火率が発生した際には、サービス、テナント、またはリージョンレベルでの迅速な無効化スイッチが必要です。

フォローアップの質問と回答

ヘッジングはリトライとどう違いますか?

リトライは通常、失敗を待ってから再送信します。ヘッジングは最初の試行がまだ実行されている間に、レイテンシの閾値が経過した時点でコピーを送信します。どちらも冪等性、デッドライン、スロットリングが必要です。

なぜp95から始めるのですか?

通常のリクエストの大部分には手を加えず、テールの小さな一部のみをカバーするためです。閾値はリクエストクラス、バジェット、実験結果に基づいて調整する必要があります。

すべてのレプリカが混雑している場合はどうしますか?

ヘッジングを停止し、レート制限、キューイング、縮退、またはフェイルファストを使用します。ヘッジングは不十分なキャパシティを修復することはできません。

キャンセルが機能していることをどのように証明しますか?

ダウンストリームのキャンセル、処理完了、コネクション占有率、解放レイテンシを記録します。遅い敗者を注入し、勝者が選択された後に停止することを確認します。

ストリーミングによって設計はどう変わりますか?

最初のバイトまたはトークンまでの時間をトリガーとして使用しますが、出力開始後に複製すると重複データが発生する可能性があります。まずストリームのマージ、キャンセル、クライアントへの可視性を定義してください。

gRPCの主要な設定項目は何ですか?

maxAttemptshedgingDelay、および致命的でないステータスコードによって、コピーを送信するタイミングを制御します。gRPCは試行回数を5に制限し、リトライスロットリングとサーバープッシュバックを提供します。サービスには独自のキャパシティバジェットが依然として必要です。

公開情報ソース

関連する質問