VPSにswapは必要?容量の決め方とzramの使い分け
多くのクラウドイメージにswapはありません。小規模VPSで追加すべき条件、容量の決め方、vm.swappinessの意味、zramが有利な場面を具体的に解説します。
VPS に swap は必要ですか?
多くのクラウドイメージには swap がありません。小規模な VPS では、通常は swap ファイルを追加するのが適切です。swap によって、1 GB のサーバーが 2 GB のサーバーのように動作するわけではありません。kernel が使用頻度の低い匿名ページを退避させる場所を確保できるため、page cache を有効に活用できます。また、OOM killer(out of memory killer。メモリを解放するためにプロセスを選んで終了させる kernel の処理)が最初に使われるのではなく、最後の手段になります。
要点は次のとおりです。いくつかの長時間稼働するサービスを実行するサーバーでは、小容量の swap ファイルは、使用するディスク容量に見合う価値があります。一方、1 つのプロセスがサーバー全体のメモリ容量を超える割り当てを定期的に試みる環境では、swap では問題を解決できません。障害の発生を遅らせ、原因を把握しにくくするだけです。このガイドでは、その2つの状況を見分ける方法と、VPS でのみ発生する2つのコストについて説明します。
以下の各コマンドは、自分のサーバー上で root が必要です。別のサーバーの出力をコピーするのではなく、自分のサーバー上で実行してください。
swap が実際に行うことと、行わないこと
Linux のメモリには 2 種類あります。ファイルにバックアップされたページは、ディスク上にすでに存在するデータのコピーです。実行中のプログラムや、最近読み取ったすべてのファイルが該当します。この集合がページキャッシュです。匿名ページは、対応するファイルがないメモリです。heap や stack に加え、実行時にデータベースが確保するメモリの大部分が該当します。
メモリが不足すると、kernel はページを回収する必要があります。変更されていないファイルバックページは、ディスク上にコピーが残っているため、回収しても後で再度読み込めます。匿名ページはそうはいきません。RAM 上のコピーしかないためです。swap がなければ、kernel が匿名メモリに対して取れる選択肢は 2 つです。保持するか、そのメモリを所有する process を kill するかです。
swap のない server でもページングは発生します。ただし、対象となるメモリが適切ではありません。メモリの負荷が高まると、kernel は page cache を縮小し、すぐに再び必要になるファイルページを追い出します。実行中のプログラムの executable text も含まれます。これらのページは major page fault として再び読み込まれます。vmstat の bi 列に disk read が表示され、/proc/vmstat の pgmajfault カウンターが増加します。一方、si と so はその間ずっと 0 のままです。system は thrashing の状態ですが、swap カウンターには何も表示されません。
swap が行わないのは、容量を増やすことです。working set、つまり実際にアクセスされているページの合計が RAM より大きい場合、swap は out of memory による kill を非常に遅い server に変えるだけです。遅い server なら login して修復できる一方、kill された database は復旧できないため、このトレードオフを選ぶ場合があります。逆に、遅い server がすべての接続を保持したまま health check に失敗し続けるため、かえって悪化する場合もあります。swap を追加する前に、どちらを選ぶのか決めてください。
クラウドイメージに swap がないのはなぜですか?
これは意図的な選択です。プロバイダーが提供するすべてのプランで起動できるように、1 つのイメージを設計する必要があります。そのため、固定サイズの swap パーティションは、小規模なプランではディスクを無駄にし、大規模なプランでは役に立ちません。swap の速度はゲストが使用するストレージにも左右されますが、イメージの作成時点ではそれを把握できません。また、イメージの作成者は予測可能な動作を重視します。プロセスがすぐに終了するほうが、すべてのサーバーで、数秒遅れであらゆる要求に応答し続けるマシンよりも診断しやすいためです。
これらの理由は、使い捨てのマシンを前提としています。維持して使う VPS は別です。VPS は交換するのではなく修復するため、数秒間のページングで済むほうが、サービスが kill されるより通常は望ましい結果になります。swap がない状態は、他者の用途に合わせたデフォルト設定だと考えてください。
VPS では swap file と swap partition のどちらを使うべきか
ファイルを使用します。パーティションを使う場合、すでにパーティション分割された状態で提供されたディスク上で、稼働中の root filesystem のサイズを変更する必要があります。これはメリットがない一方で、実際のリスクを伴います。ファイルなら通常のコマンドで作成・削除でき、パーティションテーブルに触れずに後からサイズを変更できます。
速度は決め手になりません。swapon 時点で、kernel はファイルの extent map を 1 回読み取り、その後は I/O を block device に直接送信します。そのため、各ページの swap in と swap out のたびに filesystem が経路に入ることはありません。同じディスク上であれば、swap file と swap partition の性能は同じです。
知っておくべき制限が 2 つあります。NFS(network file system)のような network filesystem 上には swap を配置しないでください。また、btrfs ではファイルの copy on write を無効にし、compression も無効にする必要があります。そのため、btrfs には swap file を作成する専用の helper が付属しています。
Ubuntu または Debian で swap ファイルを追加する方法
変更する前に、現在の状態を確認します。
swapon --show
free -h
findmnt -no FSTYPE /swapon --show の出力が空であれば、swap はまったくありません。これは新しい cloud image では通常の状態です。findmnt は root filesystem の種類を表示します。この種類によって、ファイルの作成方法が決まります。ほとんどの cloud image が使用する ext4 では、fallocate を安全に使用できます。
sudo fallocate -l 2G /swapfile
sudo chmod 600 /swapfile
sudo mkswap /swapfile
sudo swapon /swapfilechmod を mkswap より先に実行するのは意図した順序です。これを省略すると、mkswap がそのことを示します: mkswap: /swapfile: insecure permissions 0644, fix with: chmod 0600 /swapfile。全ユーザーが読み取れる swap ファイルでは、他のプロセスが swap に退避したメモリを、システム上のすべてのユーザーが読み取れます。正常な mkswap ではサイズも確認できます。出力には Setting up swapspace version 1, size = 2 GiB (2147479552 bytes) のような行が表示されます。
xfs または btrfs では、最後のコマンドが swapon: /swapfile: swapon failed: Invalid argument で失敗することがあります。XFS では、fallocate が未書き込みの extent を残すために発生します。その場合は、バイト列を直接書き込みます。
sudo dd if=/dev/zero of=/swapfile bs=1M count=2048 status=progressbtrfs では、原因は copy on write です。現在の btrfs-progs は適切なフラグを自動的に設定します。
sudo btrfs filesystem mkswapfile --size 2g /swapfileどちらの場合も、最後に chmod 600、該当する場合は mkswap、続いて swapon を実行し、結果を確認します。
swapon --show
free -hswapon --show には、type が file の /swapfile が表示され、指定したサイズも確認できます。free -h には、使用量がほとんどない Swap の行が表示されます。新しく設定した環境で使用中の swap が 0 なのは正しい状態です。kernel は必要な場合にだけページを swap へ移動します。
再起動後も有効になるように設定し、すぐにエントリをテストします。
echo '/swapfile none swap sw 0 0' | sudo tee -a /etc/fstab
sudo swapoff /swapfile
sudo swapon -a
swapon --showswapon -a は /etc/fstab を読み取るため、誤った行があれば、その場で失敗します。テストしていない typo は、計画外の再起動時に発覚します。そのとき、swap があると思っていた状態でサーバーが起動しますが、実際には swap がありません。
後で swap を削除する場合は、sudo swapoff /swapfile を実行し、fstab の行を削除してから sudo rm /swapfile を実行します。swapoff は、swap に退避されたすべてのページを先に RAM へ読み戻す必要があります。そのため、負荷の高いサーバーでは swapoff: /swapfile: swapoff failed: Cannot allocate memory で失敗することがあります。メモリを解放してから、もう一度実行します。
スワップファイルはどの程度のサイズにすべきか
この用途では、長期間使われていない anonymous page を保持します。そのため重要なのは、割り当てられたメモリのうち実際にアイドル状態になっている量であり、プランの RAM 容量ではありません。アイドル状態のメモリはプランのサイズに比例して増えないため、プランが大きくなるほど倍率を下げます。このガイドでは、次のルールを使用します。
The data behind this chart
[
{
"label": "1 GB plan",
"swap_gb": 2,
"swap_x_ram": 2
},
{
"label": "2 GB plan",
"swap_gb": 2,
"swap_x_ram": 1
},
{
"label": "4 GB plan",
"swap_gb": 2,
"swap_x_ram": 0.5
},
{
"label": "8 GB plan",
"swap_gb": 4,
"swap_x_ram": 0.5
},
{
"label": "16 GB plan",
"swap_gb": 4,
"swap_x_ram": 0.25
}
]最小プランでは、スワップを 2 GB 確保します。これは RAM の 2 倍です。1 GB のサーバーは余裕が非常に少なく、1 回のメモリ使用量急増で OOM killer が動作するためです。表の最大プランでは、スワップファイルを 4 GB、つまり RAM の 0.25 倍で止めます。これほど大量のデータを共有ストレージへページングすると処理に時間がかかり、その間サーバーが実質的に停止するためです。スワップファイルは実際にディスク容量を消費するため、ディスク容量に余裕がない場合はこれらの値を小さくしてください。
スワップを RAM と同じか、それ以上にする典型的な理由は hibernation です。hibernation では、メモリ全体のイメージをスワップへ書き込みます。VPS は hibernation を実行しないため、このルールは該当しません。
vm.swappiness は実際に何を変えるのか
vm.swappiness は RAM の割合でもしきい値でもありません。匿名ページを回収するコストとファイルページを回収するコストを、kernel が相対的にどう評価するかを示す値です。デフォルトは 60 です。値を下げると、kernel は page cache を破棄することを優先します。値を上げると、匿名メモリを swap にページアウトすることを優先します。
どちらの方向にもトレードオフがあります。vm.swappiness = 10 では、データベースは割り当てたメモリをより多く resident に保ちます。その代わり、直前に cache から破棄したファイルを再読み込みする必要があります。実際の処理の中心がファイル配信であるサーバーでは、これは適切ではありません。その場合、page cache が有用な処理を担っているためです。
値を 0 にしても swap は無効になりません。kernel がメモリ不足になる直前まで匿名ページの回収を避けるようになります。その結果、OOM killer の実行が先送りされるのではなく、早まります。swap を使用しない場合は、swap file を削除してください。
sysctl vm.swappiness
printf 'vm.swappiness = 10\n' | sudo tee /etc/sysctl.d/99-swappiness.conf
sudo sysctl --system
sysctl vm.swappiness単に sysctl -w と指定した設定は次の再起動までしか有効ではありません。その後は適用されなくなるため、/etc/sysctl.d/ にファイルを作成してください。5.8 以降の kernel は、0 から 200 までの値を受け付けます。100 を超える値が意味を持つのは、swap が RAM とほぼ同じ速度である場合だけです。これは zram を使用する場合に該当します。
zram: ディスクではなく CPU を消費する swap
zram は RAM 上に存在する圧縮ブロックデバイスです。swap として使用すると、ディスクへ書き込まれるはずのページが圧縮され、メモリ内に保持されます。ディスク I/O は発生せず、ディスク容量も消費しません。その代わり、ページの swap in と swap out のたびに CPU 時間を使います。また、圧縮ページを保持する RAM が必要になるため、その分だけアプリケーションが利用できる RAM が減ります。
匿名ページで通常公開されている圧縮率は 2:1 から 3:1 です。実際の値は、zramctl の DATA 列と COMPR 列に表示されます。一般的な値を前提にせず、実測してください。ワークロードによっては、ほとんど圧縮できないデータを保持することがあります。
sudo apt install zram-tools/etc/default/zramswap で ALGO=zstd と PERCENT=25 を設定し、サービスを再起動して結果を確認します。
sudo systemctl restart zramswap
zramctl
swapon --showPERCENT は RAM 全体に対する割合です。そのため、4 GB のシステムで 25 を指定すると、圧縮ページ用に最大 1 GB を確保します。最初は低い値から始め、zramctl でデバイスが満杯になっていることを確認した場合にだけ増やしてください。同じファイルにある PRIORITY 設定は、カーネルがどの swap を先に使用するかを決めます。値が高いものが優先されます。通常の swapon で追加したディスク上の swap ファイルには負の優先度が設定されるため、最初に zram が使用され、あふれた分をファイルが受け持ちます。swapon --show の PRIO 列に、両方の値が表示されます。systemd-zram-generator の代わりに zram-tools を使用するディストリビューションでは、同じ設定を /etc/systemd/zram-generator.conf に記述します。
zram は、CPU に余裕があり、利用できるディスク容量が少ないシステムに適しています。すでに不足しているリソースが CPU 使用量である場合は適していません。圧縮処理がアプリケーションと同じ CPU 使用枠を奪い合うためです。
VPS でのみ発生する swap の注意点 2 つ
1 つ目はディスク容量です。2 GB の swap ファイルを作成すると、必要な容量を事前に確保するため、その時点でプランのディスク容量を 2 GB 消費します。df -h / は直ちに全量分減少し、ファイルを削除するまで戻りません。小容量のプランでは無視できない割合を占めます。また、root ファイルシステムが満杯になると、swap で解消できる問題よりはるかに多くの機能が停止します。このファイルは du の出力にも含まれます。容量不足の原因を調べているときに、df と du でディスク使用量の場所が一致しないことを思い出しておくと役立ちます。
2 つ目は遅延です。swap I/O は、ホストが他のゲストと共有するストレージに送られます。ゲスト内部からは、他のゲストの負荷を確認できません。確認できるのはその影響だけです。通常は短時間で完了するページインに、ときどき大幅に時間がかかります。その間、処理はページが到着するまで停止します。これは、実行キューではなくディスクキューに適用した 共有ホストでの CPU steal timeと同じ考え方です。公開されている遅延値は別のゲストの状況を示すものなので、自分のサーバーで測定してください。
swap がシステムに悪影響を与えているか確認する方法
swap の使用量があること自体は問題ではありません。問題なのは swap への入出力です。数百メガバイトが swap に置かれていても、ページングが発生していないサーバーでは、数時間アクセスされていないメモリが移動されただけです。これは想定どおりの状態です。
合計値ではなく、レートを確認します。
vmstat 1 5si と so は、swap へのスワップインとスワップアウトの 1 秒あたりのキビバイト数です。正常なサーバーでは、swpd 列の値にかかわらず、常に 0 付近で推移します。so が継続し、同時に si も増加している場合、ページが書き出された直後に読み戻されています。これはスラッシングです。
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
r b swpd free buff cache si so bi bo in cs us sy id wa st
2 3 1048572 38210 4096 61440 912 1180 2210 1290 1402 2890 9 7 12 72 0この例はサーバーに問題があることを示しています。最も明確な指標は swap 列にはありません。wa が 72 で、CPU の大半の時間を I/O 待ちに費やしています。また、b が 3 で、3 つのプロセスがブロックされています。
PSI(pressure stall information)を使うと、この状態をより直接的に確認できます。
cat /proc/pressure/memorysome avg10=8.42 avg60=5.11 avg300=2.03 total=1284729
full avg10=3.10 avg60=1.94 avg300=0.71 total=498210some avg10=8.42 は、直近 10 秒間に、少なくとも 1 つのタスクがメモリ待ちで 8.42 パーセントの時間停止していたことを示します。full は、アイドル状態ではないすべてのタスクが停止していた時間を数えます。そのため、full の値が継続すると、単なる警告ではなく、測定可能な性能低下が発生しています。ファイルが存在しない場合、kernel では PSI がデフォルトで無効になっているため、kernel のコマンドラインに psi=1 が必要です。
どのプロセスがページを swap に保持しているかを確認するには、次を実行します。
sudo awk '/^Name:/{n=$2} /^VmSwap:/ && $2+0 > 0 {printf "%10d kB %s\n", $2, n}' /proc/[0-9]*/status | sort -rn | headOOM killer がすでに実行されたか確認するには、次を実行します。
sudo journalctl -k --grep "Out of memory"実行結果は Out of memory: Killed process 2199 (mysqld) total-vm:1275860kB, anon-rss:129252kB, file-rss:0kB, shmem-rss:0kB, UID:114 pgtables:504kB oom_score_adj:0 のようになり、同じ秒のサービスログには Main process exited, code=killed, status=9/KILL と記録されます。swap がないサーバーでこのような行を確認した場合は、次に試す対策として swap file の追加が最も低コストです。
スワップが適切な解決策ではない場合
スワップは、一時的なメモリ圧迫や使用頻度の低いメモリへの対処時間を稼ぐためのものです。終了するまで増え続けるプロセスには効果がありません。障害の監視も難しくなります。マシンがすぐに失敗して再起動する代わりに、余分な時間をページングに費やすためです。
プロセスに上限を設定してください。systemd のサービスでは、drop-in ファイルに MemoryMax= と MemorySwapMax= を指定できます。アプリケーションを変更せずに、systemd でサービスのメモリと CPU を制限する方法です。コンテナにも 1 つ上のレベルで同じ制御機能があります。設定すれば、1 つの Compose サービスがサーバー全体を使い果たすことを防げます。どちらも、カーネルにスコアで終了対象を選ばせるのではなく、ログで確認できる名前付きのプロセス終了を実現します。
サーバーが新しく、負荷の低い間に設定してください。スワップファイルの作成とメモリ上限の設定は数分で完了します。これは、新しい VPS の最初の 10 分間に行う作業の一部です。
FAQ
swap を追加すると、1 GB の VPS は 2 GB の VPS と同じように動作しますか?
いいえ。swap は RAM よりはるかに低速で、kernel は低頻度でしか使用されないと判断したページだけを swap に移します。swap によって得られるのは、負荷の急増に対する余裕と、確保された後に二度と使用されないメモリを退避する場所です。マシンの搭載量を超えるメモリをワークロードが継続的に読み書きすると、swap は out of memory による kill を絶え間ないページングに変えます。サーバーは稼働し続けますが、応答が遅すぎて実用になりません。その場合は RAM を追加するか、増加するプロセスに上限を設定してください。
1 GB または 2 GB の VPS には、どの程度の swap が必要ですか?
2 GB でどちらにも対応でき、その後は RAM に合わせて増やし続ける必要はありません。swap は低頻度でしか使用されない匿名ページを保持します。サーバー上の実際に低頻度でしか使用されないメモリ量は、総 RAM と同じようには増えません。RAM の 2 倍という古いルールは、メモリ全体のイメージをディスクに書き込む hibernation に由来しますが、VPS が hibernation することはありません。4 GB を超えて設定しても、他のゲストと共有するストレージ上で、障害が発生するまでの時間が延び、障害時の処理が遅くなるだけです。
swapping を停止するには、vm.swappiness を 0 に設定すべきですか?
いいえ。名前から想像される動作にはなりません。vm.swappiness = 0 は swap を無効にしません。kernel に対して、メモリ不足が近づくまで匿名ページの reclaim を避けるよう指示します。その結果、OOM kill が減るどころか発生しやすくなります。また、すべての reclaim が page cache に集中するため、ファイルの読み取りがより頻繁にディスクへ戻ります。swap を完全に使用しない場合は、sudo swapoff -a を実行して fstab の行を削除してください。swapping を減らす場合は、vm.swappiness = 10 を試し、実行前後で vmstat の si 列と so 列を比較してください。
swap file の代わりに zram を使用すべきですか?
CPU に余裕があり、空きディスクが少ない場合は zram を使用してください。逆の場合は swap file を使用します。zram はページを圧縮して RAM に保持するため、ディスク I/O を完全に回避できます。ただし、page in と page out のたびに CPU コストが発生し、zram が使用する領域の分だけアプリケーションが利用できる RAM は減ります。CPU の割り当てが少ない VPS では、そのコストが、すでに不足しているリソースに加わります。両方を使用する構成も一般的です。/etc/default/zramswap で PRIORITY を使用して zram の優先度を高くし、その下にディスクの swap file を残して、あふれた分を受け入れます。
free で使用可能なメモリが表示されたのに、なぜ OOM killer が実行されたのですか?
free はある時点の状態を報告しますが、メモリの割り当ては瞬時に発生します。reclaim による解放よりも速く大きな領域を要求するプロセスは、平均的には余裕があるように見えても kill されます。sudo journalctl -k --grep "Out of memory" で kernel log を読み、kill されたプロセスと、その時点の resident size を確認してください。次に、その kill がマシン全体ではなく cgroup の制限によるものかを確認します。MemoryMax= が設定されたコンテナまたは systemd unit は、host に空きメモリが残っていても、それぞれの制限に達すると kill されます。