本番サーバーでswapを設けるか判断する――メモリ超過時の落とし方と運用性の設計

本番サーバーにswapを設けるかどうかは、「メモリが足りなくなったときにどう落とすか」という判断です。swapを無効にしてOOMKillerに委ねる設計と、swapで延命しながらアラートを受ける設計は、ワークロードの特性と運用体制によって優劣が変わります。この記事では、swap有効・無効・zswapの使い分けから、swappinessの設定根拠、プロセスの落とし方の設計、コンテナ環境での考慮点、検知設計、ドキュメント化の粒度までを整理し、判断の軸を示します。

swapを有効にすべき条件とOOMKillerで落とす条件の整理

メモリ消費が一時的にスパイクするワークロードでのswapの役割

swapが有効に機能するのは、メモリ消費が常時高止まりするのではなく、バッチ処理や夜間ジョブなど一時的にピークを迎えるワークロードです。想定例として、データ集計バッチが1日1回実行され、その間だけ物理メモリを超えるような構成では、swapが「緩衝地帯」として機能します。スワップを使い切る前に処理が終わるため、深刻なパフォーマンス劣化は発生しません。一方、常時swapを踏み続ける構成ではディスクI/Oのボトルネックがサービス全体に波及するため、swap領域を確保するだけでは問題の根本解決になりません。

OOMKillerに委ねてよい条件と委ねてはいけない条件

OOMKillerに委ねる設計が有効なのは、プロセスを即座に落としてもサービスが継続できる構成です。コンテナオーケストレーターによる自動再起動が整備されていれば、OOMKillerが特定のコンテナを落としても数秒で復旧します。一方、シングルプロセスで動くデータベースや、再起動にリカバリ処理が必要なメッセージブローカーなどは、OOMKillerに落とされると復旧まで数分〜数十分を要する可能性があります。このようなプロセスを抱えるサーバーでは、swapによる延命とアラート通知を組み合わせることが判断の基本線になります。

よくある落とし穴——「とりあえずswap有効」の設計リスク

よくある落とし穴は、swap領域を確保しておけば安心という認識のまま運用を続けることです。swap使用率が上昇してもアラートが上がらず、ある日突然ディスクI/Oが飽和してサービス全体が応答不能になるケースは一般的な失敗パターンです。swapを有効にする判断と、スワップ使用時の検知設計はセットで行うべきです。また、HDDベースのサーバーでswapを使うとランダムI/Oのレイテンシが数百ミリ秒単位で跳ね上がる点も、見落とされやすいリスクです。

swap有効・無効・zswap利用の比較表

3方式の特性整理

swap有効・無効・zswapの3方式は、それぞれメモリ管理の方針が異なります。swap有効はディスクを後衛として使い、無効はメモリが枯渇した瞬間にOOMKillerが介入します。zswapはRAM上に圧縮されたスワップキャッシュを設け、ディスクへの追い出しを遅延させる中間的な設計です。圧縮率はLZ4で2〜3倍、zstdで3〜4倍程度が期待でき、実質的なメモリ容量を増やす効果があります。

方式 メモリ枯渇時の動作 パフォーマンスへの影響 主な適用場面
swap無効 OOMKillerがプロセスを即時終了 スワップI/Oが発生しないため影響なし ステートレスWebサーバー・自動再起動前提のコンテナホスト
swap有効 ディスクへのページアウトで延命 HDDで数百ms・NVMeで数十ms程度のレイテンシ増加 バッチサーバー・一時的スパイクが発生する単一サービス
zswap有効 RAMに圧縮キャッシュを置きディスクへの追い出しを遅延 CPU負荷が若干増加するが、ディスクI/Oを大幅に削減 データベースサーバー・メモリ密度の高いコンテナホスト

ワークロード別の推奨方式の選び方

ステートレスなWebアプリケーションでは、swap無効にしてOOMKillerとオーケストレーターの自動復旧に委ねる設計がシンプルです。データベースサーバーはページキャッシュの有効活用が重要なため、swappiness=1〜5でswapを有効にするかzswapを採用します。バッチ処理サーバーは一時的なメモリスパイクへの耐性が必要なため、swap有効かつswappiness=10前後が基本線になります。10台以上のコンテナホストが並ぶ環境では、各ホストの設計を揃えることで運用負荷を抑えられます。

swappinessの設定値とワークロード特性の対応関係

swappiness=0〜10が適切なワークロード

swappinessはLinuxカーネルがページキャッシュをswapに追い出す積極性を制御するパラメータで、設定範囲は0〜200です(デフォルト60)。データベースサーバーでは、ページキャッシュをメモリに残してディスクI/Oを最小化することが優先されます。swappiness=1〜10に設定することで、物理メモリが逼迫するまでswapへの追い出しを抑制できます。MySQLやPostgreSQLを運用するサーバーではswappiness=10以下が一般的な推奨値ですが、0に設定しても「絶対にswapしない」ではなく「できる限りswapしない」という意味であり、メモリが枯渇すればOOMKillerが動作します。

swappiness=30〜60前後が許容されるワークロード

Webサーバーやアプリケーションサーバーでは、プロセスの再起動コストが低く、ページキャッシュの恩恵がデータベースほど大きくない場合があります。デフォルト値付近でも大きな問題は生じませんが、レイテンシ要件が厳しいサービスではswappiness=10〜30に下げる設計が安全です。設定は即時反映できますが、再起動後も維持するには/etc/sysctl.confへの記載が必要です。手を動かす手順の詳細はサーバー構築の実作業資料を参照してください。

vm.vfs_cache_pressureとの組み合わせ設計

swappinessと合わせて検討すべきなのがvm.vfs_cache_pressureです。デフォルト値100ではdentryキャッシュとinodeキャッシュを積極的に回収します。ファイルアクセスが多いサーバーでは50〜70に下げることで、キャッシュ回収を抑制してI/Oを削減できます。swappinessとvfs_cache_pressureは独立した制御ですが、両者の組み合わせでメモリ管理の全体像が決まるため、片方だけ設定して終わる設計は不完全です。特にNFSマウントやログ大量出力サーバーでは、vfs_cache_pressureの影響がswappinessと同等以上に出ることがあります。

メモリ超過時にどのプロセスを先に落とすか設計

OOM ScoreとOOM Score Adjの仕組みと設計方針

Linuxカーネルは各プロセスにOOM Score(0〜1000)を自動計算して割り当てます。スコアが高いプロセスほどOOMKillerに狙われやすく、スコアは主にメモリ消費量の大きさで決まります。これを調整するのがoom_score_adjで、-1000〜1000の範囲で設定でき、-1000に設定するとそのプロセスはOOMKillerの対象外になります。重要なのは、保護するプロセスのスコアを下げるだけでなく、意図的に落とすプロセスのスコアを上げるか、そのままにする設計を明示的に行うことです。

保護すべきプロセスと意図的に落とすプロセスの分類

設計の基本は「落ちたときのコストが高いプロセスを保護し、再起動コストが低いプロセスを先に落とす」という方針です。想定例として、同一サーバー上にデータベースと複数のワーカープロセスが同居する構成では、データベースのoom_score_adjを-500〜-1000に設定して保護し、ワーカーは0〜200のままにしておく設計が基本です。全プロセスのスコアを下げると、メモリ枯渇時にOOMKillerが落とすべきプロセスを見つけられず、カーネルパニックに至るリスクがあります。プロセスの保護は選択的に行うことが重要です。

systemdサービスでの設定と管理単位の整合

systemdを使うサーバーでは、各サービスユニットファイルにOOMScoreAdjを記載することで、プロセス単位ではなくサービス単位での管理が可能になります。プロセスのPIDが変わる再起動時も設定が引き継がれるため、手動でoom_score_adjを書き換える運用と比べてミス発生のリスクが低く、設定の追跡もしやすくなります。AnsibleなどのIaCで一括管理する場合も、ユニットファイルに記載する形式が最もトレーサビリティを確保しやすい設計です。

コンテナ環境でのswap設定と上限制御の考慮点

Dockerの–memory-swapオプションの扱い

Dockerでは–memory-swapを明示的に指定しない場合、–memoryの2倍がswap上限として設定されます(–memory 512MBなら–memory-swap 1GB)。コンテナが意図せずswapを大量消費してホストに影響を与えないよう、–memory-swapを–memoryと同値に設定してswap利用を禁止するか、明示的な上限を設ける設計が推奨されます。–memory-swapに-1を設定すると無制限になるため、本番環境での使用は避けるべきです。

Kubernetes環境でのswap設計の変化点

Kubernetes 1.28以降、Linuxノードでのswap有効化が正式にサポートされています。以前はswap有効のノードでのkubeletは動作非推奨でしたが、現在はNodeSwapポリシーをLimitedVirtualMemoryまたはUnlimitedVirtualMemoryで制御できます。全Podへのswap許可はパフォーマンス保証を難しくするため、swap利用を許可するPodを限定する設計が安全です。特にGuaranteed QoSクラスのPodにはswapを許可しない設定が推奨されています。

コンテナ密度とswap設計の関係

10〜20コンテナが稼働するホストでは、各コンテナが少量ずつswapを踏むと、ホスト全体のディスクI/Oが意図せず高止まりする現象が発生します。この場合、個々のコンテナのメモリ上限を適切に設計してswapを踏ませない構成が根本解決です。swap設計はホスト単位だけでなく、コンテナ密度とメモリ配分の設計と一体で考える必要があります。コンテナのメモリ使用実績を2〜4週間分収集してから上限を設定するアプローチが、設計根拠の確保という観点から有効です。

スワップを踏んだ際の検知とアラートの設計

検知に必要な指標の選定

スワップ使用量の絶対値だけを監視する設計は不十分です。si(swap in)とso(swap out)のレートを合わせて監視することが重要で、これらはメモリページがswapとRAMの間を行き来する頻度を示します。使用量が増加し始めた段階ではなく、siとsoが継続的に発生している状態を検知することで、パフォーマンス劣化の予兆を早期につかめます。Prometheusを使う場合はNode Exporterのnode_vmstat_pswpinとnode_vmstat_pswpoutをレート計算して評価する設計が標準的です。

アラート閾値の設計指針

swap使用率が全体の20%を超えた時点でWarning、50%を超えた時点でCriticalとする設計が一般的な出発点です。ただし、swap容量を大きく確保しているサーバーでは絶対値での閾値設計も併用します。想定例として、swap総量が16GBのサーバーで使用率20%を閾値にすると、3.2GBのswap使用を許容することになり、その時点でパフォーマンスが既に劣化している可能性があります。siとsoの5分間平均レートが一定値を超えた場合の警告も組み合わせることで、実用的な検知設計になります。

PrometheusとAlertmanagerを使った実装方針

PrometheusでのswapモニタリングはNode Exporterが提供するnode_memory_SwapTotal_bytesとnode_memory_SwapFree_bytesから使用率を計算するのが標準的な設計です。加えてnode_vmstat_pswpinとnode_vmstat_pswpoutをrateで評価することで、ページの出入りが活発な状態を検知できます。Alertmanagerのルーティング設計では、swapのCriticalアラートをオンコール担当へ直接通知する重要度に分類しておくことが、運用上の事故を減らす設計です。

swap設計をドキュメント化する際の記載粒度

判断根拠の記載が引き継ぎの質を左右する

設定値だけをドキュメントに残す運用では、担当者が変わった際に「なぜこの値なのか」が失われます。ドキュメントには設定値とともに、判断の前提となったワークロード特性とメモリ消費パターンを記載します。想定例として「swappiness=5に設定しているのは、このサーバーがPostgreSQLを単独で運用しており、ページキャッシュの有効活用を優先するためである」という形式が、引き継ぎ時のミス抑制につながります。前提となるワークロードが変わった際に設計を見直すトリガーも明記しておくことが重要です。

ドキュメントに記載すべき項目のチェックリスト

以下の項目を記載することで、swap設計の意図と根拠を将来の担当者が正確に読み取れるドキュメントになります。

  • swapの有効・無効・zswapのいずれを採用しているか、およびその選定理由
  • swap領域のサイズと配置(専用パーティション・ファイル・zswap圧縮プールの別)
  • swappinessの設定値と、その値を選んだワークロード上の根拠
  • oom_score_adjを設定しているプロセスの一覧と保護・除外の優先順位
  • コンテナ環境での–memory-swapまたはcgroup v2のmemory.swap.maxの設定値
  • 監視指標と閾値(swap使用率・si/soレート・WarningとCriticalの基準値)
  • アラート発報時の初動対応フロー(誰が何をするか)
  • 設計を見直すトリガー(トラフィック増加率・メモリ増設のタイミングなど)

定期レビューの仕組みと設計変更の記録方法

サーバーのワークロードは時間とともに変化するため、swap設計も定期的な見直しが必要です。半年〜1年に1回、実際のswap使用率の推移とsiおよびsoのレートを確認し、設定変更が必要かどうかを判断する運用を組み込みます。サービスのトラフィックが増加している局面では、メモリ増設とswap設計の見直しを同時に検討することが適切です。設計変更を行った際は、変更内容と変更時点のワークロード状況をセットでドキュメントに追記することで、数年後の担当者が経緯を追えるようになります。

▶ 手を動かして本番まで到達する

その設計判断を、RHEL10の本番環境で手を動かして固めませんか

ここまでの設計判断は、読めば腹に落ちます。ですが「自分の手で本番まで通しきる自信」は、それとは別の話になります。

最大6名の少人数で、構築実務者の到達点まで引き上げます。座学で終わらせず、本番相当の環境で判断を検証する2日間です。

本番サーバーのメモリ管理とswap設計を体験する上級Linuxハンズオンへ →

Linuxセミナー上級編(RHEL10)|最大6名の少人数ハンズオン