代表的な面接トピック

バックエンド面接:Kubernetesのグレースフルシャットダウンとコネクションドレイニングの設計

バックエンド普通
Offer.cc 編集チーム公開日 更新日

質問

ローリングリリースやノードメンテナンスの最中に、HTTP Podでリクエストの欠落が時折発生します。新規ワークの受付停止、長時間接続のドレイン、重複バックグラウンドジョブの防止、およびterminationGracePeriodSecondsが十分であることの証明をどのように行いますか?

プロンプトとスコープ

あるHTTPサービスがDeploymentで稼働しています。Podが削除された後も一部のリクエストが古いインスタンスに届き続け、ロングポーリングやバックグラウンドジョブが中断されます。Kubernetes、Service、ロードバランサー、およびプロセス全体にわたる終了タイムラインを説明し、ドレイニング、キャンセル、リトライ、および検証を設計してください。コアとなるスキルはシャットダウン中の接続と副作用の境界を適切に定めることであり、バックエンド領域に属します。

面接官が評価するポイント

優れた回答では、Podの削除、EndpointSliceの更新、ロードバランサーの伝播、preStop、SIGTERM、およびSIGKILLを明確に区別します。SIGTERMの受信はトラフィックが停止したことを意味しません。長時間接続、キュージョブ、冪等なリトライ、予期せぬノードの電源喪失、および不十分な猶予期間を網羅してください。

最初に明確にすべき質問

  • サービスは短いリクエスト、SSE、WebSocket、ロングポーリングのどれですか?接続は移行可能ですか?
  • Readiness、Liveness、Startupプローブは何をチェックしていますか?また、アプリケーションはドレイン状態を公開していますか?
  • preStopはsleep、HTTPフック、またはアプリケーションのドレインエンドポイントですか?最終的な終了は誰が実行しますか?
  • Podはワーカーを実行していますか?また、リースや重複配信はどのように処理されますか?
  • Ingressロードバランサー、サービスメッシュ、クラウドLBの伝播遅延はどれくらいですか?

30秒の回答フレームワーク

「まずアプリケーションをnot-readyとしてマークして新しいワークの受け入れを停止し、エンドポイントとロードバランサーの伝播を待ちます。ドレイニングに移行し、短いリクエストを完了させ、長時間接続を切断または移行し、ワーカーが新しいジョブを取得するのを止めると同時に完了できないリースを解放します。preStopは調整のための猶予枠に過ぎず、SIGTERMがクリーンアップを実行します。猶予期間はp99の伝播、ドレイニング、クリーンアップをカバーする必要があり、期限切れ後にのみSIGKILLが送信されます。リクエストの欠落や重複した副作用がないことを証明するため、接続とジョブのメトリクスを用いてリリースをテストします。」

ステップバイステップの解決策

タイムラインを描きます。コントローラーがPodを削除し、kubeletが終了処理を開始し、EndpointSliceとロードバランサーが非同期にエンドポイントを削除します。コンテナはSIGTERMの前にpreStopを実行することがあります。伝播は非同期であるため、古いアドレスにトラフィックがまだ届いている場合でも、アプリケーションは自身がドレイニング中であることを認識した時点で直ちに新しいワークを拒否しなければなりません。

readydrainingの状態を別々に保持します。シャットダウンパスはドレイニングを設定し、Readinessを失敗させ、新規接続の受け入れを停止するか、リトライ可能なレスポンスを返します。既存の短いリクエストは完了させます。SSE、WebSocket、およびロングポーリングには終了シグナル、カーソル、または再開トークンを送信し、クライアントが安全に再接続できるようにします。

preStopのsleepはアプリケーションロジックの代わりにはなりません。伝播時間を稼ぐだけであり、猶予期間を消費します。開始時刻と残りのバジェットを記録するアプリケーションのドレインエンドポイントを優先してください。SIGTERMハンドラーは新規ワークを停止し、リスナーを閉じ、アクティブなリクエストを待ち、コネクションプールを解放します。

ワーカーのドレイニングはHTTPのドレイニングとは別に設計します。新しいメッセージの取得を停止します。アクティブなジョブをリースまたは可視性タイムアウトで保護し、残りのバジェットが不足している場合は別のワーカーがリトライできるようにそれらを解放します。ジョブの書き込みや外部への副作用には冪等性キーが必要です。強制終了されたPodが二重に課金したり発送したりしてはなりません。

測定されたp99値(Ingress伝播、許容される最長リクエスト時間、接続の切断、ワーカのクリーンアップ、ログのフラッシュ、およびジッターマージン)に基づいてterminationGracePeriodSecondsを選択します。期限が切れるとkubeletは強制終了を実行できるため、未完了のリクエストやプロセス内の状態がfinallyの実行に依存することはできません。

ノードメンテナンスはPodの削除とは異なります。KubernetesのグレースフルノードシャットダウンはkubeletとPodに計画されたウィンドウを与えますが、電源喪失、カーネルパニック、ホストの強制再起動ではそれが与えられません。重要なジョブには永続的なチェックポイント、複数のレプリカ、キューベースのリカバリが必要です。

ローリングリリース、手動削除、ノードドレイン、LB伝播遅延、長寿命接続、SIGTERM後のタイムアウトを検証します。5xx、切断、完了率、ドレインによる拒否、ジョブリトライ、重複した副作用、エンドポイント削除遅延、強制Pod終了をすべてリリースバージョンと関連付けて確認します。

質の高い模範解答

「私はpreStop: sleep 30をグレースフルシャットダウンとして扱いません。シャットダウンシグナルを受け取ると、アプリケーションは自身をドレイニング中としてマークし、Readinessを失敗させ、新規ワークの受け入れを停止します。エンドポイントとLBの更新は非同期で伝播するため、古いインスタンスは新しいリクエストを明示的に拒否します。短いリクエストは完了させ、SSEやWebSocket接続は切断または再開トークンを受け取り、ワーカーはジョブの取得を停止して完了できないリースを解放します。

preStopは伝播時間を稼ぐだけです。SIGTERMハンドラーはリスナーを閉じ、アクティブなリクエストを待ち、プールを解放して、単一の期限内に終了します。猶予期間は、測定されたp99の伝播、最長リクエスト、ワーカクリーンアップ、ログフラッシュから算出します。テストではローリングリリース、ノードドレイン、長時間接続、クラッシュ、強制終了をカバーし、リクエストの欠落、重複した副作用、未回復のジョブがないことを確認します。」

よくある間違い

  • SIGTERMのみを待機する → 伝播中のトラフィックが古いPodに届き続ける → まずReadinessを失敗させてドレイニングに入る。
  • ドレイニングの代わりに固定のsleepを使用する → 伝播やリクエスト時間の変化で破綻する → 残り期限に基づいてロジックを制御する。
  • Podを停止しながらキュージョブを取得し続ける → 強制終了により処理が重複する → 取得を停止してリースを解放する。
  • 長時間接続を通常のリクエストとして扱う → クライアントが再開できない → 終了シグナルとカーソルを送信する。
  • 平均レイテンシから猶予期間を見積もる → p99のリクエストがSIGKILLされる → テールレイテンシと伝播時間を測定する。
  • finallyが常に実行されると想定する → 強制終了や電源喪失でクリーンアップがスキップされる → 重要な状態を永続化する。
  • Podステータスのみを監視する → LBの伝播遅延や切断を見落とす → エンドポイント、リクエスト、リリースメトリクスを関連付ける。
  • ドレイニング中にLivenessを失敗させる → 再起動ストームを引き起こす → Readinessはトラフィック適格性を意味し、Livenessはプロセスの健全性を意味する。

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

フォローアップ1:Readinessが失敗した後もリクエストが到達するのはなぜですか?

エンドポイント、サービスメッシュ、クラウドロードバランサーの更新は遅延を伴って伝播し、既存の接続は自動的には移行されません。ドレイニング中のアプリケーションは、新規ワークを拒否し、既存の接続を安全に閉じる必要があります。

フォローアップ2:preStopのsleepはどれくらいの長さにすべきですか?

推測で決めてはいけません。エンドポイントとLBの伝播p99を測定し、それをリクエストおよびワーカのクリーンアップバジェットと組み合わせ、sleepを境界のある調整ウィンドウとして扱います。

フォローアップ3:WebSocketを適切に切断するにはどうすればよいですか?

新規接続の受け入れを停止し、再接続のガイダンスを含む切断コードを送信します。クライアントがセッションまたはカーソルで再開できるようにし、副作用の再実行を防ぐのに十分な状態を永続化します。

フォローアップ4:ジョブの途中でPodが停止した場合はどうなりますか?

ジョブの状態とリースを永続化します。可視性タイムアウトの経過後、新しいワーカーがそれを取得します。冪等性キーや状態クエリにより外部への副作用を保護します。プロセス内のfinallyに依存してはいけません。

フォローアップ5:ノードの電源喪失はグレースフルに対処できますか?

確実には対処できません。計画的なノードシャットダウン処理は観測可能なメンテナンスフローをカバーしますが、電源喪失やカーネルクラッシュにはレプリカ、永続チェックポイント、およびリトライ可能なジョブが必要です。

フォローアップ6:猶予期間はどのように選択しますか?

エンドポイント伝播、最大リクエスト時間、長寿命接続の切断、リース解放、接続クリーンアップ、ログフラッシュを加算し、平均値ではなく測定されたp99とマージンを用いて検証します。

フォローアップ7:ドレイニング中の再起動ストームを回避するにはどうすればよいですか?

Livenessを健全に保ちながらReadinessのみを失敗させます。「一時的にトラフィックを受け付けない」状態がクラッシュしたプロセスと誤認されないように、プローブの責務を分離します。

公開情報ソース

関連する質問