プロンプトとスコープ
あるクラスタで、API サーバを呼び出すスケジューリングプラグインを有効にしています。API のレイテンシが上昇すると、同期呼び出しがスケジューリングサイクルを占有し、未スケジュールの Pod が蓄積してしまいます。優先度キュー、リクエストの合流(coalescing)、リトライ、キャンセル、公平性、ロールバックを網羅しつつ、KEP-5229 で説明されている非同期アプローチを設計してください。
面接官がテストしているポイント
- シリアルなスケジューリングサイクルのセマンティクスと、非同期な API の副作用を適切に分離できているか。
- 有界な優先度キューと合流処理によって、枯渇(starvation)と重複書き込みを防げているか。
- 冪等性キー、デッドライン、キャンセル、古い(stale)結果、永続エラーを定義できているか。
- 優先度の公平性、バックプレッシャー、メトリクス、フィーチャーゲートによるロールアウトをカバーできているか。
確認すべき質問
- その呼び出しは読み取り、冪等な書き込み、あるいは外部リソースの作成のどれですか? 副作用によってリトライの制限が決まります。
- プラグインは結果整合性のある外部状態を許容できますか、それともバインド前に状態を確認する必要がありますか?
- 失敗した場合、Pod をスケジュール不可(unschedulable)として再キューイングしますか、それとも API 操作のみをリトライしますか? それらのループは分離しておく必要があります。
- クラスタ API の QPS、並行スケジューリングレベル、キューのバジェットはどの程度ですか?
30 秒で答えるフレームワーク
低速な API 操作をスケジューリングスレッドから有界な優先度キューに移します。スケジューラは冪等性キーを付与したタスクを投入し、他の Pod の処理を継続します。同一キーを合流させながら、Pod の優先度と待機時間順に処理します。完了時は安全な再評価をトリガーするのみとし、古い結果によって Pod がバインドされないようにします。エラーはデッドライン、キャンセル、バックオフ、並行性制限とともに、リトライ可能と永続エラーに分類します。キューの深さ、待機時間、成功率、スケジューリングレイテンシを使用してフィーチャーゲート配下でロールアウトし、しきい値を超えた場合は非同期パスを無効化してフォールバックします。
ステップごとの詳細解説
1. 同期の境界を定義する
スケジューリングサイクルはノードを選択してスケジューリングコンテキストを保持し、非同期タスクは遅延が許容される処理を実行します。結果がバインドの必須前提条件である場合は、保留中(pending)としてモデル化し、確認が取れるまでバインドを阻止します。現在のサイクルを損なわない処理のみを非同期化できます。
2. 有界な優先度キューを構築する
各タスクは、Pod の UID、操作タイプ、冪等性キー、デッドライン、およびキャンセルコンテキストを保持します。キューには容量制限を設けます。キューが満杯になった場合は、無制限にメモリを消費するのではなく、明示的なバックプレッシャーシグナルを返します。高優先度の処理を優先して提供し、エイジングやクォータによって恒久的な枯渇を防ぎます。
submit(key, priority, deadline, operation)
if same key is pending: coalesce(operation)
else if queue is full: return Backpressure
else enqueue(operation)3. 合流処理と冪等性
合流(coalescing)は、1 つの論理操作に対する並行リクエストをマージするものであり、API サーバの冪等性を提供するものではありません。書き込みには、安定したリソースキー、条件付き更新、またはサーバ側の冪等性が必要です。外部リソースが二重に作成されないよう、リトライ前に以前の結果を確認します。異なるバージョンや対象宛てのリクエストは、文字列が似ているという理由だけでマージしてはなりません。
4. 完了、キャンセル、および古い結果の処理
関連する Pod に再評価を要求する完了イベントを発行します。スケジューリング状態が有効なままであると仮定してはなりません。Pod が削除されたり、プリエンプトされたり、新しいスケジューリングコンテキストに入った場合はタスクをキャンセルします。デッドラインを過ぎた結果は破棄し、その理由を記録します。期限切れのコンテキストからの API 呼び出しが成功しても、古いバインドを実行してはなりません。
5. リトライ、バックプレッシャー、および公平性
タイムアウト、一時的なネットワークエラー、および 429 応答は、指数バックオフを用いてリトライします。認証エラー、無効なパラメータ、コンフリクトは、永続エラー処理または再計算が必要です。ワーカー数、プラグインごとのクォータ、API の QPS を制限します。Pod のスケジューリングリトライと API タスクのリトライは個別にカウントします。そうしないと、1 つの低速な操作によってキューが過大に膨らむ可能性があります。
6. 互換性、ロールアウト、およびロールバック
プラグイン API とスケジューリングセマンティクスを維持しながら、非同期パスをフィーチャーゲート配下に配置します。リスクの低いプラグインや並行度の低いクラスタから開始します。スケジューリング P99、キュー待機時間、API レイテンシ、タスク失敗、重複リクエスト、スケジュール不可のリトライを比較します。バックログ、バインドエラー、または API への負荷がベースラインを超えた場合は、新規タスクの投入を停止し、タスクをドレインまたはキャンセルして同期パスに戻します。
模範解答の例
まず、どの呼び出しが遅延可能で、どれがバインドの前提条件かを分類します。前者は有界な優先度キューに入れ、後者は明示的な pending 状態として表現します。Pod UID、操作タイプ、冪等性キー、デッドライン、キャンセルコンテキストを含め、同一キーを合流させ、満杯時はバックプレッシャーを適用します。ワーカーは冪等または安全にリトライ可能な操作のみを実行し、一時的なエラーにはバックオフを適用し、永続エラーはプラグインのエラーハンドリングに渡します。完了時は再評価をトリガーし、無条件にバインドすることは決してありません。フィーチャーゲート配下でロールアウトし、スケジューリング P99、キューの深さ、API QPS、重複率、失敗率、バインドの正確性を測定します。違反が発生した場合は、投入を停止し、タスクをクリーンアップしてフォールバックします。
よくある間違い
- すべての呼び出しをバックグラウンドに送る → バインドの前提条件がバイパスされる可能性がある → まずスケジューリング状態遷移図を描く。
- 単一のグローバル FIFO を使用する → 優先度の高い Pod が優先度の低い処理の後ろで待たされる → 優先度、エイジング、クォータを追加する。
- リクエストのテキストで重複排除する → バージョンや副作用が誤ってマージされる可能性がある → リソースキーと明示的な冪等性を使用する。
- 無限にリトライする → API 停止がキューの急増を引き起こす → デッドライン、バックオフ、試行回数制限、サーキットブレーカーを使用する。
- スループットのみを測定する → レイテンシや正確性のリグレッションが見落とされる → キュー、API、リトライ、バインドを監視する。
フォローアップ質問と回答
同じ Pod に対する読み取りと書き込みを合流させることはできますか?
Pod UID だけで合流させることはできません。読み取りはリソースバージョンによって合流できる場合がありますが、書き込みは操作タイプ、対象、冪等性キーが必要であり、必要な順序付けを維持しなければなりません。
キューが満杯の場合、どのタスクを破棄すべきですか?
デッドライン、優先度、再構築可能性に基づいて判断します。破棄不可能なバインド前提条件はバックプレッシャーを発生させるべきです。破棄されたタスクは、サイレントに削除するのではなく、必ず説明可能なリトライまたは失敗状態に導く必要があります。
Pod がプリエンプトされた後に API 呼び出しが成功した場合はどうなりますか?
古いコンテキストがそれ以上書き込みを行わないよう、キャンセルとオブジェクトバージョンのチェックを使用します。監査のために成功記録は残し、古いバインド意図を再利用するのではなく、新しいスケジューリングコンテキストに再計算させます。