Linuxメモリスワップネスとキャッシュ動作のチューニングにおけるベストプラクティス
LinuxのスワップネスとVFSキャッシュ動作を注意深くチューニングし、ワークロード例、sysctlコマンド、検証手順を紹介します。
Linuxメモリスワップネスとキャッシュ動作のチューニングにおけるベストプラクティス
Linuxは空きRAMを積極的に使用します。free -hでサーバーの「空き」メモリが非常に少ないのを初めて見た人は驚くかもしれません。そのメモリのほとんどはページキャッシュ、dentry、inodeキャッシュであり、メモリリークではありません。難しいのは、カーネルがRAMを適切に活用しているのか、メモリ回収がアプリケーションに悪影響を及ぼし始めているのかを見極めることです。
Linuxメモリチューニングでよく登場する2つのsysctl設定がvm.swappinessとvm.vfs_cache_pressureです。これらは便利ですが、魔法のパフォーマンススイッチではありません。不適切な値を設定すると、本当の問題を隠したり、あるワークロードから別のワークロードに問題を移したりする可能性があります。
Linuxメモリ管理パラメータの理解
Linuxはヒューリスティックを使用して、システムがより多くの空きRAMを必要とするときにどのメモリページを回収するかを決定します。カーネルパラメータによって制御される主な領域は、スワッピング(非アクティブなメモリページをディスクに移動する)とキャッシング(ファイルシステムのメタデータとデータをRAMに保持する)の2つです。
1. vm.swappiness
vm.swappinessは、カーネルがプロセスを物理メモリからディスク上のスワップ領域に移動させる傾向を決定します。0から100までの値を取ります。
- 高い値(例:60、一般的なデフォルト値): カーネルは匿名メモリを回収し、通常のメモリ管理の一部としてスワップを使用する傾向が強くなります。これによりページキャッシュを保持できますが、アクティブなページが追い出されるとレイテンシに敏感なサービスに悪影響を及ぼす可能性があります。
- 低い値(例:10以下): カーネルはプロセスをスワップアウトする前に、ページキャッシュからメモリを回収することを優先します。これにより、実行中のアプリケーションをRAMに長く保持し、応答性を向上させますが、システムが頻繁にキャッシュページをドロップする必要がある場合、ディスクI/Oパフォーマンスが低下する可能性があります。
- 値0: カーネルは可能な限りスワッピングを回避しますが、スワップが無効になるわけではありません。スワップを無効にする必要がある場合は、
swapoffを使用し、まずメモリ不足のリスクを理解してください。
vm.swappinessの実践的な適用
最適な設定はワークロードに大きく依存します:
| ワークロードタイプ | 推奨swappiness範囲 |
根拠 |
|---|---|---|
| データベースサーバー、ハイパフォーマンスコンピューティング(HPC) | 1 - 10 | スワップレイテンシがキャッシュドロップよりも悪い場合の良い出発点となることが多い。実際のワークロードメトリクスで検証すること。 |
| 汎用サーバー、デスクトップ | 30 - 60 | スワップ動作が問題を引き起こしているという証拠がない限り、通常は妥当。 |
| ファイルサーバーやキャッシュ主体のシステム | 場合によっては60以上 | ページキャッシュを保持できるが、ワークロードにとって断続的なスワッピングが許容される場合にのみ意味がある。 |
現在の値を確認する方法:
cat /proc/sys/vm/swappiness
一時的に値を変更する方法(再起動まで):
swappinessを10に設定する場合:
sudo sysctl vm.swappiness=10
永続的に値を変更する方法:
/etc/sysctl.confファイルを編集し、以下の行を追加または変更します:
# /etc/sysctl.conf
vm.swappiness = 10
保存後、再起動せずに以下のコマンドで変更を適用します:
sudo sysctl -p
メモリ集約型のデータベースの場合、1から10が一般的な出発点です。これをルールとして扱わないでください。PostgreSQLやMySQL/InnoDBなど、独自のバッファキャッシュを既に持っているデータベースは、通常、スワップを避けることで恩恵を受けます。ファイルサーバーはより大きなページキャッシュを好むかもしれません。RAMが少なすぎる小さなVMは、どの数値を選んでも問題が発生します。
2. vfs_cache_pressure
vfs_cache_pressureは、カーネルがディレクトリとinodeメタデータ(VFSキャッシュ)に使用されるメモリをどの程度積極的に回収するかを制御します。
- この値は0から1000の範囲です。
- デフォルト値は通常100です。
値が100の場合、カーネルはVFSキャッシュメモリの回収とページキャッシュ(ディスクデータ)に使用されるメモリの回収のバランスを取ります。値100は、メモリプレッシャーが存在する場合、カーネルがページキャッシュメモリの1部分ごとにinode/dentryキャッシュメモリの1部分を回収しようとすることを意味します。
vfs_cache_pressureの調整
- 値を増やす(例:> 100): カーネルがVFSキャッシュメモリをより積極的に回収するようにします。これによりRAMがより早く解放されますが、メタデータをディスクから再度読み取る必要があるため、その後のファイルシステムルックアップが遅くなる可能性があります。
- 値を減らす(例:< 100): カーネルがVFSキャッシュの回収をより控えめにします。これにより、ディレクトリとinode情報がメモリに長く保持され、繰り返しのファイルシステム操作が高速化されます。
vfs_cache_pressureを減らすべき場合:
システムが同じ大きなディレクトリ構造に頻繁にアクセスする場合(複雑なアプリケーション、コンテナオーケストレーション、特定のネットワーク設定で一般的)、この値を低く設定する(例:50)と、メタデータをRAMで利用可能に保つことでパフォーマンスが向上します。
vfs_cache_pressureを増やすべき場合:
システムが全体的なメモリプレッシャーに悩まされており、未使用のメモリを迅速に回収したい場合、この値を上げることがありますが、これは値を下げるよりも一般的ではありません。
現在の値を確認する方法:
cat /proc/sys/vm/vfs_cache_pressure
永続的に値を変更する方法:
/etc/sysctl.confを編集します:
# /etc/sysctl.conf
vfs_cache_pressure = 50
sudo sysctl -pで変更を適用します。
警告: 非常に低い
vfs_cache_pressureの値は、カーネルがディレクトリとinodeキャッシュを予想よりも長く保持する可能性があります。これはメタデータ主体のワークロードには役立つかもしれませんが、アプリケーションのメモリプレッシャーを悪化させる可能性もあります。効果を測定しない限り、極端な値は避けてください。
包括的なチューニングシナリオ
これらのパラメータの適切な組み合わせを選択することで、アプリケーションの安定性とファイルシステムキャッシングの間のトレードオフを最適化します。
シナリオ1: データベースサーバー(メモリ優先)
目標: アプリケーションメモリの常駐を最大化し、スワッピングを何としても最小限にする。
vm.swappiness = 5vfs_cache_pressure = 50(ディレクトリデータをある程度キャッシュするが、RAMが逼迫した場合はVFSメタデータよりもアプリケーションメモリを優先する)。
変更を加える前に、データベースが実際にスワッピングしているかどうかを確認します:
free -h
vmstat 1
grep -E 'pswpin|pswpout' /proc/vmstat
クエリレイテンシのスパイク中にスワップインとスワップアウトのカウンタが上昇している場合、swappinessを下げると効果があるかもしれません。スワップが使用されておらず、データベースが遅い場合、swappinessが問題ではありません。クエリプラン、バッファヒット率、チェックポイント、ディスクレイテンシ、接続プレッシャーなどを調査してください。
シナリオ2: 高ディスクI/Oサーバー(キャッシュ優先)
目標: 頻繁にアクセスされるファイルデータをページキャッシュに保持することで、ディスクパフォーマンスを最大化する。
vm.swappiness = 80(ディスクキャッシュ拡張のためにRAMを解放するために、より早くスワッピングを許可する)。vfs_cache_pressure = 100(inodeとページキャッシュの標準的なバランス)。
これは、人々が最も過剰にチューニングしがちなシナリオです。サーバーが同じファイルを繰り返し読み取る場合、ページキャッシュは重要です。しかし、システムがキャッシュを保持するためにアクティブなワーカープロセスをスワップし始めると、ファイルシステムキャッシュが健全に見えても、ユーザーはレイテンシの悪化を経験する可能性があります。キャッシュサイズだけでなく、アプリケーションの応答時間を監視してください。
シナリオ3: 仮想化ホストまたは汎用システム
目標: 複数のワークロードにわたって安定したパフォーマンスを実現する。
vm.swappiness = 30(デフォルトの60よりもアクティブなVM/プロセスをRAMに少し長く保持するが、制御されたスワッピングを許可する中程度の設定)。vfs_cache_pressure = 100(デフォルトで十分なことが多い)。
仮想化ホストは、ゲストメモリの動作がホストレベルのチューニングを誤解させる可能性があるため、特別な注意が必要です。バルーニング、オーバーコミット、ゲストスワップはすべて相互作用する可能性があります。ゲストメモリを大量にスワップするホストは、各ゲストが自身のワークロードを正常と認識していても、VM内部に痛みを伴うレイテンシを生み出す可能性があります。
より安全なチューニングワークフロー
/etc/sysctl.confを編集することから始めないでください。まず、設定が関連していることを証明することから始めましょう。
通常の負荷時にベースラインを取得します:
free -h vmstat 1 10 cat /proc/sys/vm/swappiness cat /proc/sys/vm/vfs_cache_pressureパフォーマンス低下期間中に同じデータを取得します。プロセスレベルのメモリを追加します:
ps -eo pid,comm,rss,vsz,%mem --sort=-rss | head -20一時的に1つの値を変更します:
sudo sysctl vm.swappiness=10ワークロードを十分な時間実行して動作を観察します。スワップアクティビティの低下、アプリケーションレイテンシの改善、新しいファイルシステムの速度低下がないかを確認します。
現実的なテスト期間をクリアした後にのみ、値を永続化します。
/etc/sysctl.d/を使用するシステムでは、/etc/sysctl.confに追記するよりも、専用の小さなファイルの方がクリーンなことがよくあります:
sudo tee /etc/sysctl.d/90-memory-tuning.conf >/dev/null <<'EOF'
vm.swappiness = 10
vm.vfs_cache_pressure = 100
EOF
sudo sysctl --system
設定管理システムがsysctl設定を管理している場合は、代わりにそこに変更を加えてください。1台のサーバーでの手動のsysctl編集は忘れやすく、再現も困難です。
free -hをパニックにならずに読む
典型的なfree -hの出力では、freeの下に小さな数値、buff/cacheの下に大きな数値が表示されることがあります。これは正常です。Linuxは最近使用されたファイルデータをメモリに保持します。未使用のRAMは誰の役にも立たないからです。
available、スワップ使用量、そして現在スワップアクティビティが発生しているかどうかに注目してください。サーバーは過去のメモリスパイクからスワップを割り当てているが、現在スワップの変動がない場合があります。これは、常にスワップイン/スワップアウトを行っているサーバーほど緊急性は高くありません。
以下を使用します:
vmstat 1
通常の負荷でsiとsoがほぼゼロのままの場合、その時点でスワップがレイテンシを積極的に引き起こしているわけではありません。アプリケーションが停止している間にそれらがゼロ以外のままである場合、メモリプレッシャーが深刻な原因である可能性があります。
これらの設定をチューニングすべきでない場合
swappinessやキャッシュプレッシャーを変更することが最初の修正として適切でないケースがいくつかあります。
サーバーにスワップが設定されていない場合、vm.swappinessは実質的な効果をほとんど発揮しません。ポリシーの一貫性のためにチューニングすることはできますが、それ自体でメモリプレッシャーを解決することはできません。
スワップが小さな緊急用パーティションとしてのみ存在する場合、設定の効果も限定的です。カーネルはスワップを使用するタイミングを選択できますが、数百メガバイトの緊急用スペースを本格的なメモリ階層に変えることはできません。そのような設定では、OOMリスクとサービスの制限に焦点を当ててください。
プロセスに実際のメモリリークがある場合、swappinessを下げると問題が先延ばしになります。リークは成長し続けます。サービスを再起動すると一時的に容量が回復するかもしれませんが、永続的な修正はアプリケーションレベル(リークの修正、メモリの制限、同時実行性の低減、ワークロードの変更)です。
ディスクが障害ドライブ、ストレージのスロットリング、または飽和したクラウドボリュームのために遅い場合、メモリチューニングは一部の読み取りを減らすことができますが、ストレージの障害を修正することはできません。iostat、カーネルログ、クラウドボリュームメトリクス、SMART/NVMeのヘルスを確認してください。
ワーキングセットがRAMよりも大きい場合、完璧なsysctl値はありません。より多くのメモリ、より少ない同時実行性、より小さなキャッシュ、異なるデータレイアウト、またはワークロードの分割が必要です。
コンテナとKubernetesに関する注意事項
コンテナではメモリチューニングがさらに難しくなります。コンテナは、ホストに空きRAMがある場合でも、cgroupのメモリ制限に達する可能性があります。ホストのswappiness設定は依然として重要ですが、即時の症状はポッドまたはコンテナ内のOOMキルである可能性があります。
cgroupとオーケストレーターのシグナルを確認します:
dmesg -T | grep -i 'killed process'
docker stats
kubectl describe pod <pod-name>
Kubernetesの場合、ノードレベルのsysctlを変更することは、ノードプール設定の一部として行うべきであり、1回限りのシェルセッションではありません。また、一部のsysctlは名前空間化されており、一部はノードレベルであることを覚えておいてください。vm.swappinessとvm.vfs_cache_pressureは、典型的なLinuxシステムではホストレベルの設定であるため、変更するとそのノード上のすべてのワークロードに影響します。
監視と検証
変更を適用した後、影響を検証するために継続的な監視が重要です。free、vmstat、システムパフォーマンス監視ダッシュボードなどのツールを使用します。
vmstatの使用:
si(スワップイン)とso(スワップアウト)の列を監視します。swappinessが低い健全なシステムでは、通常の負荷でsiとsoの値が低いかゼロであるべきです。
vmstat 5 10
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----\ r b swpd free buff cache si so bi bo in cs us sy id wa st
0 0 0 123456 102400 5123456 0 0 0 5 40 70 1 1 98 0 0
swappinessを減らした後もsoの値が高いままの場合、ワークロードはおそらくより多くの使用可能なメモリまたはより低いメモリ需要を必要としています。より多くのRAMが1つの答えですが、唯一の答えではありません。ワーカー数を減らしたり、アプリケーションキャッシュを縮小したり、データベースメモリをチューニングしたり、リークを修正したり、サービスをホスト間で分割したりすることもできます。
vm.swappinessとvm.vfs_cache_pressureを普遍的なアップグレードとしてではなく、ワークロードの設定として扱ってください。実用的な道は退屈ですが信頼性があります:現在のスワップと回収動作を測定し、1つの設定を変更し、実際の負荷でテストし、アプリケーションの動作が改善された場合のみ変更を維持します。