OOMポリシーのマスター:メモリ不足イベントへのsystemdの応答を調整する
Linuxシステムは堅牢に設計されていますが、高負荷時やメモリリークにより、利用可能なメモリが不足する場合があります。この状況が発生すると、カーネルのOut-of-Memory (OOM) killerが呼び出され、プロセスを終了させてメモリを解放し、システム全体のクラッシュを防ぎます。しかし、デフォルトのOOM killerの動作は常に最適とは限らず、重要なサービスが終了する可能性があります。Systemdは、多くのLinuxディストリビューションにおける最新のinitシステムおよびサービスマネージャーとして、システムがメモリ枯渇に直面した際にプロセスがどのように扱われるかを微調整するための強力なツールを提供します。
この記事では、systemdユニットファイル内の OOMScoreAdjust および OOMPolicy ディレクティブに焦点を当て、systemdのOOM (Out-Of-Memory) ポリシーの設定方法について掘り下げます。これらの設定を理解し操作することで、カーネルがどのプロセスを犠牲にするかを選択する度合いを大幅に影響させ、それによって重要なアプリケーションを保護し、メモリ不足の条件下でのシステム安定性を確保できます。
Linux OOM Killerの理解
systemdの設定に入る前に、OOM killerがどのように動作するかを理解することが重要です。カーネルが割り当て要求を満たすために解放できるメモリがないことを検出すると、OOM killerが呼び出されます。このメカニズムは、実行中のプロセスをスキャンし、それぞれのプロセスに「悪さ」または終了の可能性を示す oom_score を割り当てます。大量のメモリを消費するプロセス、長時間実行されているプロセス、または oom_score が高いプロセスは、終了の候補となる可能性が高くなります。
oom_score は、メモリ使用量、プロセスの優先度、およびプロセスが実行されていた時間など、いくつかの要因に基づいて計算されます。カーネルは次に、システムを稼働状態に保つのに十分なメモリを回収することを期待して、最も高い oom_score を持つプロセスを選択してキルします。これは効果的ですが、このプロセスは受動的であり、誤って oom_score が高くなった場合、重要でないプロセス、あるいは重要なプロセスさえも終了させることがあります。
SystemdとOOM制御
Systemdは、個々のサービスに対するOOM動作を管理するための、より詳細なアプローチを提供します。カーネルのグローバルOOMスコアにのみ依存するのではなく、systemdユニットによって管理されるプロセスの oom_score に影響を与え、OOM条件下でのこれらのユニットの動作方法に関する特定のポリシーを定義することさえできます。
OOMScoreAdjust ディレクティブ
Systemdユニットファイルで利用可能な OOMScoreAdjust ディレクティブは、そのユニットによって開始されたプロセスの oom_score に直接影響を与えることができます。これは、ユニットのメインプロセスに対して /proc/[pid]/oom_score_adj ファイルの oom_score_adj 値を調整することによって実現されます。
- 値:
OOMScoreAdjustの範囲は -1000 から 1000 です。 - -1000 の値は、プロセスをOOM killerから保護します。
- 1000 の値は、プロセスを終了の最有力候補にします。
- 0 の値は、
oom_score_adjが変更されないことを意味し、プロセスのoom_scoreはカーネルのデフォルトロジックによって決定されます。
仕組み: Systemdがサービスを開始すると、対応するプロセスの oom_score_adj を設定できます。oom_score_adj の値が低いほど、プロセスの oom_score は減少し、キルされる可能性は低くなります。逆に、値が高いほど oom_score は増加します。
例: OOMイベント中に重要なデータベースサービスが終了する可能性を低くするには、そのsystemdユニットファイル(例:/etc/systemd/system/mydatabase.service)に以下を追加することが考えられます。
[Service]
ExecStart=/usr/bin/my-database-server
OOMScoreAdjust=-500
この例では、OOMScoreAdjust=-500 により my-database-server プロセスの oom_score が大幅に減少し、OOM killerにターゲットにされる可能性がはるかに低くなります。OOMScoreAdjust=-1000 を設定すると、効果的に保護されます。
ヒント: OOMScoreAdjust=-1000 は極めて慎重に使用してください。プロセスを完全に保護すると、そのプロセスにメモリリークがある場合、他の必須プロセスを枯渇させる可能性があり、システムが不安定になることがあります。
OOMPolicy ディレクティブ
OOMPolicy ディレクティブは、特定のユニットに対するOOM状況の処理方法について、systemdにさらに具体的な指示を提供します。システムがメモリプレッシャーを経験し、ユニットのプロセスが終了対象と見なされた場合の動作を決定します。
- 可能な値:
inherit(デフォルト): ユニットは親cgroupからOOMポリシーを継承します。これが最も一般的な設定です。continue: プロセスはキルされず、システムは動作を続行します。根本的な問題が解決されていない場合、さらなるメモリ枯渇につながる可能性があります。kill: プロセスはOOM killerによってキルされます。critical: ユニットをクリティカルとしてマークします。システムは、このクリティカルユニット内のプロセスをキルする前に、非クリティカルプロセスをキルしてメモリを解放しようとします。special:special:container: コンテナユニットがこのポリシーでマークされている場合、OOM条件が発生するとコンテナ全体がキルされます。special:stop: OOM条件が発生すると、サービスはキルされずに停止します。
例: Webサーバーをクリティカルとして指定し、他の非クリティカルプロセスが先に終了するようにします。
[Service]
ExecStart=/usr/bin/nginx
OOMPolicy=critical
例: OOM killerにキルされるのではなく、サービスを正常に停止させます。
[Service]
ExecStart=/usr/local/bin/my-batch-job
OOMPolicy=special:stop
この構成により、メモリプレッシャーが高いときに my-batch-job プロセスにクリーンなシャットダウンをシグナル送信し、即座に終了されるのではなく、可能であれば現在のタスクを完了させることができます。
警告: continue ポリシーは非常にまれに使用してください。プロセスがメモリプレッシャーに寄与しており、続行が許可されている場合、問題が悪化し、システム全体フリーズまたは制御不能なクラッシュにつながる可能性があります。
実用的な適用とベストプラクティス
- クリティカルサービスの特定: システムの運用に不可欠なサービス(例:データベース、クリティカルアプリケーションバックエンド、コアネットワークサービス)を特定します。これらはOOMポリシー調整の最有力候補です。
OOMScoreAdjustで微調整: クリティカルサービスの場合、OOMScoreAdjustを使用してoom_scoreを下げます。中程度の値(例:-200から-500)から始め、システムの動作を監視します。必要に応じてのみ調整を増やし、プロセスを保護することのリスクには常に注意してください。OOMPolicy=criticalの活用: 絶対に不可欠なサービスの場合、OOMPolicy=criticalは堅牢なオプションです。これにより、クリティカルサービスを検討する前に、システムは他のプロセスをキルすることを優先します。- 正常なシャットダウンのための
OOMPolicy=special:stopの検討: サービスを安全に停止して再起動できる場合、special:stopを使用すると、即時キルよりも制御されたシャットダウンが可能になります。 - システムメモリの監視: OOMポリシーの調整は、受動的な対策です。最善のアプローチは、システムメモリ使用量を積極的に監視し、メモリ枯渇の根本原因(例:メモリリーク、RAM不足、非効率なアプリケーションコード)に対処することです。
- 徹底的なテスト: OOMポリシーの変更を適用した後、負荷下でシステムを徹底的にテストし、望ましい動作が達成され、意図しない結果が生じないことを確認します。
- 変更の文書化: 各変更の理由を含め、ユニットファイルに加えられたすべてのOOMポリシー構成の記録を保持します。
OOM調整の検証
ユニットファイルを変更し、systemdをリロードした後(sudo systemctl daemon-reload および sudo systemctl restart <service-name>)、実行中のプロセスの oom_score_adj を検証できます。
まず、systemdユニットによって管理されているプロセスのPIDを見つけます。
systemctl status <service-name>
出力の Main PID を探します。
次に、そのPIDの oom_score_adj 値を確認します。
cat /proc/<PID>/oom_score_adj
値が OOMScoreAdjust 設定を反映していれば、構成は正しく適用されています。
結論
SystemdのOOM制御ディレクティブである OOMScoreAdjust と OOMPolicy は、管理者がメモリ不足時のシステム動作を管理するための不可欠なツールを提供します。これらの設定を慎重に調整することで、システムの回復力を大幅に向上させ、システムが深刻なメモリプレッシャー下にある場合でも、クリティカルサービスが利用可能であることを保証できます。これらの構成は、システム安定性に関するより広範な戦略の一部であり、OOMイベントを完全に防止するための最も効果的な方法は、積極的なメモリ管理であることを忘れないでください。