代表的な面接トピック

総合面接:cgroup v2 の memory.high と memory.max を使ってコンテナのリスクをどのように制御するか?

一般難しい
Offer.cc 編集チーム公開日 更新日

質問

コンテナは cgroup v2 上で動作しています。プラットフォームは、ノイズの多いバッチテナントからレイテンシに敏感なサービスを保護しつつ、異常なメモリ増加を抑制しなければなりません。memory.min、memory.low、memory.high、memory.max、および memory.oom.group について説明し、設定、監視、および障害訓練を設計してください。

設問とコンテキスト

プラットフォームチームは、ピーク時にあるテナントのバッチコンテナがオンラインサービスを圧迫する可能性があることに気づきました。ノードは cgroup v2 を使用していますが、チームはメモリリミットを1つしか設定しておらず、回収(reclaim)、スロットリング(throttling)、強制終了(termination)を区別できていません。保護境界、イベント監視、およびロールバックを備えた階層的なメモリポリシーを設計してください。

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

  • memory.min/low による保護、memory.high による回収/スロットリング、および memory.max による強制制限を区別できているか。
  • 階層的な memory.events とローカルな memory.events.local を理解しているか。
  • OOM グループ強制終了(OOM group killing)、子 cgroup、バースト、オーバーコミットを適切に扱えるか。
  • カーネルファイルをオーケストレーション、アラート、および訓練に結びつけられるか。

最初に確認すべき明確化のための質問

  1. クリティカルなワークロードの保護、テナントの制限、ノード全体の保護のどれを目的としていますか?
  2. ワークロードはレイテンシに敏感ですか、バッチ処理型ですか、それとも回収して再試行しても安全ですか?
  3. cgroup の階層構造はどうなっていますか?また、親グループにはサイドカーが含まれていますか?
  4. Kubernetes がワークロードを管理していますか?また、requests と limits は cgroup v2 にどのようにマッピングされますか?
  5. OOM は1つのプロセスを終了すべきですか、cgroup 全体を終了すべきですか、それともコントローラにコンテナを再構築させるべきですか?

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

保護レベルには memory.min と memory.low を、早期回収およびスロットリングの境界には memory.high を、最終的なハードリミットには memory.max を使用します。memory.oom.group は OOM 処理をグループ全体で行うかどうかを決定します。ノードからテナント、ワークロードへとバジェットを割り当て、memory.current、memory.events、PSI を監視し、カナリアリリース、負荷テスト、ロールバックで検証します。Kubernetes では、YAML だけを信頼するのではなく、レンダリング後に実際の cgroup ファイルを読み取ります。

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

ステップ 1: セマンティックモデルを構築する

memory.min は、強い負荷がかかった場合にのみ使用量が回収されるハードな保護境界です。memory.low は、深刻な負荷下で回収される可能性があるベストエフォート型の保護です。memory.high は回収とスロットリングをトリガーしますが、OOM killer を直接呼び出すことはありません。memory.max は超えてはならない上限であり、回収で要求を満たせない場合は cgroup OOM に入る可能性があります。

ステップ 2: 親と子のバジェットを割り当てる

システムとクリティカルなサービスのためにノードの容量を確保し、各テナントの親グループに上限を割り当ててから、オンライン、バッチ、サイドカーのワークロード用に子グループを設定します。子の保護は、親の利用可能なバジェットを無条件に超えることはできません。各レベルの現在の使用量、イベント、ポリシーのバージョンを記録します。一時的なスパイクが即座に max OOM にならないよう、high の下にバースト用のヘッドルームを残します。

ステップ 3: high と max の関係性を選択する

memory.high により、カーネルが回収とスロットリングを先に適用できるようになります。アプリケーションは、レイテンシ、スループット、イベントを観測した後に速度を落とすことができます。memory.max は最終的な安全弁であり、回復可能性を反映している必要があります。high が低すぎると恒常的なスロットリングが発生し、max が高すぎると親やノードに負荷を波及させてしまいます。両方を負荷テストで調整します。

ステップ 4: OOM グループポリシーを決定する

密結合されたプロセスの場合、memory.oom.group=1 を使用して OOM 処理をグループ全体に適用することで、メインプロセスのみが強制終了された後にヘルパープロセスが取り残されないようにします。独立したバッチジョブでは、1つのプロセスのみが終了し、キューがそれを再試行する方式が好まれる場合があります。どちらの選択肢でも、終了原因、再起動、未完了の作業を記録します。OOM は見えない再試行ではありません。

ステップ 5: memory.events を監視する

memory.events は階層構造であるため、子イベントが親に現れることがあります。memory.events.local はローカルイベントのみを報告します。highmaxoomoom_kill のデルタ(差分)を監視し、memory.current、ワーキングセット、PSI、レイテンシ、キューの経過時間と関連付けます。新しいキーが追加される可能性があるため、ファイルの行順に依存するのではなく、キーをパースしてください。

ステップ 6: ポリシーをオーケストレーションにマッピングする

Kubernetes では、requests、limits、QoS、ノードの cgroup モードを合わせて確認します。レンダリング後、コンテナに入って /sys/fs/cgroup を読み取り、実際の値を確認し、ランタイムがそれらを上書きしていないことを検証します。サイドカー、init コンテナ、共有 emptyDir のアカウンティングを確認します。親が high や max に達している最中でも、子は正常に見えることがあります。

ステップ 7: 訓練、リリース、ロールバックを実施する

単一ノードのカナリア環境で high を徐々に下げ、回収とスロットリングを観察した後、max および oom.group による強制終了をテストします。持続的な high、最初の max、実際の oom_kill に対して個別にアラートを設定します。以前のバージョンとイベントのスナップショットを含む、バージョニングされたポリシーを公開します。ノードに負荷が残らないよう、まずバジェットをロールバックし、その後に強制終了されたジョブとキューの再試行を調整します。

質の高い模範回答

保護には min と low を、観測可能な回収とスロットリングには high を、最終的なハード境界には max を使用します。親子階層を通じてノード、テナント、ワークロードのバジェットを割り当て、回復可能性に基づいて oom.group を選択します。階層的 memory.events とローカル memory.events を PSI、レイテンシ、キューの経過時間、再起動とともに監視します。Kubernetes では、レンダリングされた cgroup ファイルを検証します。カナリアリリースと負荷訓練を用いてロールアウトし、バージョニングされたロールバックポリシーを保持します。

よくある間違い

  • memory.high を即座の OOM 制限として扱うこと。
  • memory.low を破られることのない保証として扱うこと。
  • ランタイムの cgroup ファイルを読まずにコンテナの YAML を信用すること。
  • 親の階層イベントとローカルイベントを混同すること。
  • 冪等性、部分的な作業、再試行の嵐を確認せずに OOM 後に再起動すること。

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

フォローアップ 1: memory.high を超えると何が起きますか?

カーネルが回収とスロットリングの負荷を適用します。プロセスは継続できますが、レイテンシが上昇する可能性があります。これは OOM-killer のスイッチではありません。high カウンタを PSI およびサービスのレイテンシと関連付けてください。

フォローアップ 2: high が存在するのに、なぜ memory.max を維持するのですか?

high は負荷がかかった際にワークロードがリソースを譲譲できるようにし、max は回収不可能な増加を制限して親やノードを保護します。max は回復可能性と再起動ポリシーを考慮して設計する必要があります。

フォローアップ 3: なぜ memory.events はイベントを2重にカウントしているように見えることがあるのですか?

親の memory.events にはデフォルトでサブツリーのイベントが含まれますが、memory.events.local はその cgroup にローカルです。アラートごとに1つのレベルを選択し、階層構造によって重複を排除してください。

フォローアップ 4: どのような場合に memory.oom.group を有効にすべきですか?

1つの cgroup 内のプロセスが一緒に生存および再起動しなければならない場合に有効にします。独立したタスクは個別に終了できます。どちらの選択肢でも、クリーンアップ、再試行、およびオブザーバビリティのテストが必要です。

フォローアップ 5: Kubernetes のマッピングが正しいことをどのように証明しますか?

対象ノード上で、コンテナ cgroup の memory.min、memory.low、memory.high、memory.max、および events を読み取ります。これらをレンダリングされた requests、limits、QoS、ランタイム設定と比較し、負荷訓練を実行します。

公開情報ソース

関連する質問