代表的な面接トピック

Kubernetes 面接対策:kube-scheduler の API 呼び出しを非ブロッキングにするにはどうすればよいか?

システム設計難しい
Offer.cc 編集チーム公開日 更新日

質問

kube-scheduler のスケジューリングサイクル内で低速な API 呼び出しが実行される場合、Pod の順序付け、リトライ、可観測性を維持しながら、これらを非ブロッキングにするにはどう設計しますか?

プロンプトとスコープ

あるクラスタで、API サーバを呼び出すスケジューリングプラグインを有効にしています。API のレイテンシが上昇すると、同期呼び出しがスケジューリングサイクルを占有し、未スケジュールの Pod が蓄積してしまいます。優先度キュー、リクエストの合流(coalescing)、リトライ、キャンセル、公平性、ロールバックを網羅しつつ、KEP-5229 で説明されている非同期アプローチを設計してください。

面接官がテストしているポイント

  • シリアルなスケジューリングサイクルのセマンティクスと、非同期な API の副作用を適切に分離できているか。
  • 有界な優先度キューと合流処理によって、枯渇(starvation)と重複書き込みを防げているか。
  • 冪等性キー、デッドライン、キャンセル、古い(stale)結果、永続エラーを定義できているか。
  • 優先度の公平性、バックプレッシャー、メトリクス、フィーチャーゲートによるロールアウトをカバーできているか。

確認すべき質問

  1. その呼び出しは読み取り、冪等な書き込み、あるいは外部リソースの作成のどれですか? 副作用によってリトライの制限が決まります。
  2. プラグインは結果整合性のある外部状態を許容できますか、それともバインド前に状態を確認する必要がありますか?
  3. 失敗した場合、Pod をスケジュール不可(unschedulable)として再キューイングしますか、それとも API 操作のみをリトライしますか? それらのループは分離しておく必要があります。
  4. クラスタ API の QPS、並行スケジューリングレベル、キューのバジェットはどの程度ですか?

30 秒で答えるフレームワーク

低速な API 操作をスケジューリングスレッドから有界な優先度キューに移します。スケジューラは冪等性キーを付与したタスクを投入し、他の Pod の処理を継続します。同一キーを合流させながら、Pod の優先度と待機時間順に処理します。完了時は安全な再評価をトリガーするのみとし、古い結果によって Pod がバインドされないようにします。エラーはデッドライン、キャンセル、バックオフ、並行性制限とともに、リトライ可能と永続エラーに分類します。キューの深さ、待機時間、成功率、スケジューリングレイテンシを使用してフィーチャーゲート配下でロールアウトし、しきい値を超えた場合は非同期パスを無効化してフォールバックします。

ステップごとの詳細解説

1. 同期の境界を定義する

スケジューリングサイクルはノードを選択してスケジューリングコンテキストを保持し、非同期タスクは遅延が許容される処理を実行します。結果がバインドの必須前提条件である場合は、保留中(pending)としてモデル化し、確認が取れるまでバインドを阻止します。現在のサイクルを損なわない処理のみを非同期化できます。

2. 有界な優先度キューを構築する

各タスクは、Pod の UID、操作タイプ、冪等性キー、デッドライン、およびキャンセルコンテキストを保持します。キューには容量制限を設けます。キューが満杯になった場合は、無制限にメモリを消費するのではなく、明示的なバックプレッシャーシグナルを返します。高優先度の処理を優先して提供し、エイジングやクォータによって恒久的な枯渇を防ぎます。

text
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 呼び出しが成功した場合はどうなりますか?

古いコンテキストがそれ以上書き込みを行わないよう、キャンセルとオブジェクトバージョンのチェックを使用します。監査のために成功記録は残し、古いバインド意図を再利用するのではなく、新しいスケジューリングコンテキストに再計算させます。

公開情報ソース

関連する質問

関連面接ツール

システム設計の回答には「回答する」を使用

まず要件を明確にし、スケール、アーキテクチャ、コンポーネント選定、トレードオフの順に進めます。

ツールを見る