FreeBSDとLinuxのZFS、VPSでRAMは足りる?
ZFSはチェックサム、スナップショット、send/receive、圧縮が使えます。一方、ARCがRAMを消費します。2 GBや4 GBのVPSで導入前に確認すべき判断基準を解説します。
ZFS が提供するものと、必要になるもの
FreeBSD と Linux の ZFS は現在、OpenZFS という 1 つのコードベースで開発されているため、両方のシステムで機能は同じです。ZFS を実行するサーバーでは、チェックサム付きデータ、データが変更されるまで容量を消費しないスナップショット、zfs send によるレプリケーション、プロパティを 1 つ設定するだけで利用できる圧縮が得られます。一方で、メモリが必要です。ARC(adaptive replacement cache)はデフォルトで RAM の大きな割合を使用します。2 GB または 4 GB の VPS(virtual private server)では、そのメモリはアプリケーションがまさに必要としているリソースです。
このガイドでは、40 個のドライブベイを備えたストレージ装置ではなく、仮想ディスクが 1 台または 2 台あるレンタル VPS を前提に ZFS を評価します。その環境でも有用な機能こそ、時間をかける価値があります。利用環境を変えると役に立たなくなる部分もあります。プールを構築する前に把握しておくべき点です。
FreeBSD と Linux の OpenZFS: 1 つのコードベース、2 つのパッケージング事情
FreeBSD では、最初は実験的な機能として、2008 年の FreeBSD 7.0 以降、ZFS がベースシステムに含まれています。2020 年 12 月の OpenZFS 2.0 以降、FreeBSD と Linux は同じソースツリーからビルドされるため、zfs と zpool は両方で同じように動作し、一方で作成したプールをもう一方でインポートできます。
Linux では ZFS がパッケージとして提供され、FreeBSD ではベースシステムの一部になっている理由は、ライセンスにあります。OpenZFS は CDDL (common development and distribution license) の下で提供されています。Linux カーネルは GPL (general public license) version 2 の下で提供されています。カーネルプロジェクトではこの 2 つを互換性のないライセンスとして扱っているため、ZFS のコードは mainline Linux に統合されていません。そのため、各ディストリビューションが提供方法を決めています。FreeBSD にはこのような競合がないため、ZFS がそのまま含まれています。実際には、パッケージングに 1 つ違いがあるだけで、どちらか一方を選ぶ必要はありません。
SSD Nodes は FreeBSD イメージを提供していないため、ここで借りるサーバーでは、このガイドの Linux 側が該当します。別の場所で FreeBSD を運用する場合は、FreeBSD サーバーで ZFS を利用できます。モジュールをビルドする必要も、カーネルのアップグレードに対応する必要もありません。
ZFS をインストールしてプールを作成する
Ubuntu ではモジュールが kernel packages に含まれているため、コマンドだけをインストールします。
sudo apt update
sudo apt install -y zfsutils-linux
zfs versionzfs version は、userland version と kernel module version の 2 行を出力します。1 行しか表示されない場合、モジュールがロードされていません。パッケージは universe コンポーネントにあり、Ubuntu server images ではデフォルトで有効になっています。apt で見つからない場合は、最初に sudo add-apt-repository universe を実行します。
Debian ではパッケージが contrib コンポーネントにあり、モジュールは DKMS(dynamic kernel module support)によってマシン上でビルドされます。/etc/apt/sources.list.d/debian.sources の Components: 行に contrib を追加し、sudo apt update を実行してから、次を実行します。
sudo apt install -y linux-headers-$(dpkg --print-architecture) zfs-dkms zfsutils-linuxインストール時にモジュールがコンパイルされ、数分かかる Building initial module for 6.12.0-... が出力されます。これは、kernel upgrade のたびにモジュールが再ビルドされるという意味です。ビルドに失敗すると、修正するまでプールを import できません。
FreeBSD では何もインストールされていません。サービスを有効化して起動します。
sysrc zfs_enable=YES
service zfs start次にプールを作成します。まず、安定したデバイスパスを確認します。/dev/vdb は検出順に割り当てられるため、別のボリュームを接続すると変わる可能性があります。
ls -l /dev/disk/by-id/
sudo zpool create -o ashift=12 tank /dev/disk/by-id/virtio-abc123def456
zpool status tankzpool status は、デバイスが tank の下に表示された状態で state: ONLINE を出力するはずです。ashift=12 はプールの最小ブロックサイズを 4 KiB に固定します。これは現在の SSD に適していますが、作成後は変更できません。
多くのレンタルイメージは ext4 root から起動するため、ここでの ZFS は root filesystem ではなく、2 台目のボリューム上の data pool として使用します。作成前に、デバイスが想定したものか確認してください。購入した NVMe disk の確認には 1 分しかかかりませんが、再構築には午後いっぱいかかることがあります。
チェックサムによる修復にはプールの冗長性が必要です
ZFS が書き込むすべてのブロックにはチェックサムが付加され、読み取り時に毎回検証されます。検出は常に機能します。修復には 2 つ目のコピーが必要です。
単一ディスクのプールでは、ZFS は事実を通知して処理を終了します。zpool status -v では次のように表示されます。
status: One or more devices has experienced an error resulting in data
corruption.
action: Restore the file in question if possible. Otherwise restore the
entire pool from backup.
errors: Permanent errors have been detected in the following files:
/tank/data/archive.tar問題のあるファイル名が表示されます。ext4 なら、そのバイト列を何も通知せずに返していたため、これだけでも有用です。ただし、プール内に修復元となる 2 つ目のコピーがないため、ZFS でも修復できません。
ミラー構成では、同じ読み取りが正常な側から処理され、問題のあるブロックが書き直されます。このイベントは zpool status の CKSUM 列に表示されます。これが自己修復であり、2 台のデバイスが必要です。
sudo zpool create -o ashift=12 tank mirror /dev/disk/by-id/DISK1 /dev/disk/by-id/DISK2VPS では、ホストのストレージも通常はすでに冗長化されており、ハイパーバイザー上の RAID 10 が使われることもよくあります。これにより、ドライブの故障からは保護されます。しかし、どのコピーが正しいかをアレイは判定できないため、ブロックの内容が不正な状態で返されたことまでは分かりません。ZFS は、自身が書き込んだチェックサムとデータを比較するため、それを検出できます。
仮想ディスクが 1 台で、ある程度の修復機能が必要な場合は、sudo zfs set copies=2 tank/important を使用すると、そのデータセットのすべてのブロックを同じディスク上に 2 コピー保存できます。データセットが使用する容量は 2 倍になりますが、不良ブロックには対応できます。ただし、ボリューム全体が消失した場合には何もできません。
スクラブでは、プール内のすべてのデータを読み取り、検証します。
sudo zpool scrub tank
zpool status tank正常なプールでは、scan: scrub repaired 0B in 00:04:11 with 0 errors のような行で終了します。スケジュールを設定して実行してください。小規模なプールであれば、月 1 回で十分です。
systemctl list-unit-files 'zfs-scrub*'
sudo systemctl enable --now zfs-scrub-monthly@tank.timerポリシーの単位はデータセットです
データセットはプール内のファイルシステムです。作成コストが低いため、ジョブごとに 1 つ作成します。プロパティはプールから下位へ継承されるので、デフォルトを 1 回設定し、必要な場所だけ上書きします。
sudo zfs create tank/data
sudo zfs create tank/pg
sudo zfs set compression=lz4 tank
sudo zfs set atime=off tank
sudo zfs set quota=20G tank/data
sudo zfs set recordsize=16K tank/pg
zfs get -r compression,compressratio,quota tank圧縮は、慎重になって無効にされがちなプロパティですが、これは逆です。lz4 は CPU を少し使用し、ディスクへ書き込むバイト数を減らすため、圧縮可能なデータでは通常、読み取りと書き込みが速くなります。zstd は CPU を多く使う代わりに、より強く圧縮します。ログや、頻繁には読み戻さないアーカイブに適しています。実際の圧縮結果は zfs get compressratio tank で確認します。また、この圧縮率に含まれるのは、プロパティ設定後に書き込まれたデータだけです。
recordsize は、データセットが書き込むブロックの最大サイズです。デフォルトは 128K です。データベースが 8 KiB のページを 128 KiB のレコードに書き込むと、1 回の小さな書き込みでレコード全体の読み取り、変更、再書き込みが発生します。データを読み込む前に、データベースのデータセットで recordsize=16K を設定します。このプロパティが適用されるのは、新しく書き込まれたブロックだけだからです。
quota は、1 つのデータセットによるプールの全消費を防ぐための設定です。ZFS プールは使用率が 100% 近くになると遅くなり、整理も難しくなります。そのため、意図的に空き容量を残します。
スナップショットはデータが変更されるまで容量を消費しません
ZFS は使用中のブロックを上書きしません。新しいブロックに書き込み、ポインターを更新します。これがコピーオンライトです。スナップショットは、「このデータセットが現時点で指しているブロックを保持する」という記録です。そのため、作成は瞬時に完了し、容量も消費しません。
sudo zfs snapshot tank/data@2026-08-11
zfs list -t snapshot -o name,used,refer -r tank/dataスナップショットの USED 列は、そのスナップショットだけが保持している容量を示します。最初はほぼゼロですが、データを変更または削除すると増加します。古いブロックを解放できなくなるためです。
ファイルを戻すために、復元処理を実行する必要はありません。
ls /tank/data/.zfs/snapshot/
cp /tank/data/.zfs/snapshot/2026-08-11/notes.txt /tank/data/notes.txt.zfs ディレクトリは、sudo zfs set snapdir=visible tank/data を実行するまで ls -a からも隠されています。必要になる前にスナップショットを作成してください。スナップショットがない状態で誤って rm -rf を実行すると、ext4 の復旧手順に進むことになります。そこではディスクのアンマウントから始まり、以降の作業はさらに難しくなります。
ロールバックすると、スナップショット以降に書き込まれたすべての内容が破棄されます。
sudo zfs rollback tank/data@2026-08-11新しいスナップショットが存在すると、ロールバックは拒否されます。-r を実行すると、それらの新しいスナップショットを削除して処理を続行できます。Enter キーを押す前に、データセット名を必ず再確認してください。
スナップショットはバックアップではありません。 同じプール、同じボリューム、同じサーバー上に保存されます。ボリュームの障害や、zpool destroy 1 つの障害によって、データとともにスナップショットも失われます。スナップショットは、操作ミスによる rm やアップグレードの失敗から保護します。これは実際に多く発生するインシデントの多くをカバーしますが、プール自体に発生した障害からは保護しません。詳細については、VPS のスナップショットがバックアップではない理由を参照してください。
送受信: 1 つのコマンドでレプリケーション
zfs send はスナップショットを標準出力のバイトストリームに変換し、zfs receive はそのストリームをデータセットに戻します。最初のコピーはフル送信です。
sudo zfs snapshot tank/data@daily-2026-08-11
sudo zfs send tank/data@daily-2026-08-11 | ssh backup.example.com "sudo zfs recv -F backup/data"その後は、2 つのスナップショット間で変更された内容だけを送信します。
sudo zfs snapshot tank/data@daily-2026-08-12
sudo zfs send -i tank/data@daily-2026-08-11 tank/data@daily-2026-08-12 | ssh backup.example.com "sudo zfs recv backup/data"受信側には、送信元となるスナップショットが保持されていなければなりません。保持されていない場合、差分を適用するベースが ZFS にないため、受信は cannot receive incremental stream: most recent snapshot of backup/data does not match incremental source で停止します。両側が保持しているスナップショットから送信するか、フル送信でやり直します。
リモートの root を使う代わりに、送信先で権限を付与します: sudo zfs allow -u backupuser create,mount,receive backup/data。
これは、1 つの条件付きで実用的なオフサイトバックアップです。送信先は ZFS プールでなければなりません。オブジェクトストレージはストリームを受信できないためです。送信先が S3 互換ストレージまたは通常の Linux ホストの場合は、その環境に対応したツールを使用します。VPS からの restic バックアップで、その方法を説明しています。
ZFS が大量の RAM を使用するのはなぜですか? ARC
ARC(adaptive replacement cache)は、ZFS の読み取りキャッシュです。通常の Linux ページキャッシュではなくカーネルメモリ上に置かれるため、free -h では buff/cache として表示されません。使用中のメモリとして表示されます。使用率がほぼ 100% に見える ZFS サーバーは、通常、キャッシュが温まっている状態です。これが、「ZFS に RAM を食い尽くされた」という報告の大半を説明します。
デフォルトの上限は、意図的に余裕を持たせています。OpenZFS 2.3 では、ARC の最大サイズは「RAM - 1 GiB」と「RAM の 5/8」の大きい方です。OpenZFS 2.2 以前の Linux では RAM の半分を使用していましたが、FreeBSD ではすでに新しいルールを使用していました。自分の環境に適用されるルールを確認するには、zfs version を実行します。
The data behind this chart
[
{
"label": "2 GB VPS",
"openzfs_2_2_linux_gib": 1,
"openzfs_2_3_gib": 1.25
},
{
"label": "4 GB VPS",
"openzfs_2_2_linux_gib": 2,
"openzfs_2_3_gib": 3
},
{
"label": "8 GB VPS",
"openzfs_2_2_linux_gib": 4,
"openzfs_2_3_gib": 7
},
{
"label": "16 GB VPS",
"openzfs_2_2_linux_gib": 8,
"openzfs_2_3_gib": 15
}
]これらの数値は、実行中のサーバーで測定した値ではなく、一般的なインスタンスサイズに文書化されたデフォルトルールを適用したものです。4 GB のインスタンスでは、2.3 のルールにより ARC に 3 GiB を割り当てられます。同じサーバーで 2.2 を使用すると、2 GiB で上限に達します。2 GB のインスタンスでも、2.3 のルールでは 1.25 GiB まで使用できます。アプリケーションが使用できるのは、残りのメモリです。
表をそのまま信頼せず、実際のサーバーから正確な数値を確認します。
grep -E '^(size|c_max) ' /proc/spl/kstat/zfs/arcstats
arc_summary | head -n 203 列目はバイト単位です。c_max は現在適用されている上限で、size は ARC が現在保持しているサイズです。
ARC はメモリを解放します。カーネルがメモリプレッシャーを通知すると、ARC は縮小します。ただし、縮小はメモリプレッシャーによって発生するため、処理が一度に数百 MiB を要求すると、ARC が解放中であっても OOM(out of memory)killer によって終了させられることがあります。データベースと Web サーバーを 2 GB のサーバーで実行している場合、これは珍しいことではありません。OpenZFS のマニュアルにも手動変更について同じ説明があり、上限を下げても「縮小を促すメモリプレッシャーがなければ ARC は縮小しない」とされています。
小規模 VPS で ARC の上限を設定する方法
まず、ワークロードに必要なメモリ量を決めます。データベースとアプリケーションに必要な量を合計し、オペレーティングシステム用の余裕を確保して、残りを ARC に割り当てます。Postgres と 1 つの Web アプリケーションを 4 GB のインスタンスで実行する場合、ARC は 512 MiB から 1 GiB から始めるのが妥当です。
実行中の値をバイト単位で設定します。ここでは 1 GiB にします。
echo 1073741824 | sudo tee /sys/module/zfs/parameters/zfs_arc_max再起動後も維持されるようにします。
echo 'options zfs zfs_arc_max=1073741824' | sudo tee /etc/modprobe.d/zfs.conf
sudo update-initramfs -uinitramfs の手順が重要なのは、root ファイルシステムがマウントされる前にモジュールが initramfs から読み込まれる可能性があるためです。その場合、直前に作成したファイルは読み込まれません。再起動後、arcstats の c_max 行で値を確認します。
注意点が 2 つあります。これはマニュアルにも記載されています。システムの稼働中に値を 0 に戻すことはできません。そのため、元に戻すにはファイルを編集して再起動します。また、数値を下げても、大きな ARC がその場ですぐに縮小するわけではありません。
FreeBSD では、同じ上限を vfs.zfs.arc 配下の sysctl で設定します。sysctl vfs.zfs.arc を実行して現在の値と、使用中のバージョンで使われる正確な名前を確認し、その最大値を /boot/loader.conf に書き込みます。
小規模サーバー向けのメモリに関するルールがさらに 2 つあります。重複排除は無効にしてください。重複排除テーブルはメモリ上に保持され、一般的な目安では、一意なデータ 1 TB あたり 1 から 3 GB の RAM が必要です。また、swap を zvol(プールから切り出したブロックデバイス)に置かないでください。メモリを解放しようとしているファイルシステムを経由して swap すると、マシンがデッドロックする可能性があります。swap は通常のパーティション、またはプールの外部にある swap file に置いてください。
ext4 または XFS と restic の方が適切な場合
ZFS は、余裕のあるメモリと 2 つ目のボリュームがあるサーバーで効果を発揮します。それ以外では、通常のファイルシステムと適切なバックアップツールの組み合わせが適しています。次の場合は ext4 または XFS を選択してください。
- インスタンスの RAM が 2 GB または 4 GB で、ワークロードがそのメモリをすべて必要としている。
- 仮想ディスクが 1 つしかなく、2 つ目のコピーもないため、ZFS の検出機能だけでは修復できない。
- バックアップ先がオブジェクトストレージまたは通常の Linux ホストで、そこでは
zfs sendストリームを受け取れない。 - DKMS を使用する Debian を運用しており、モジュールがビルドされない状態でカーネルをアップグレードする余裕がない。
- root ファイルシステムで ZFS が必要だが、プロバイダーのイメージが ext4 しか提供していない。
データ用の別ボリュームがあり、十分な RAM(8 GB 以上が快適)を確保でき、スナップショットと zfs send を有効にするだけでなく、それらを活用する計画がある場合は ZFS を使用してください。それ以外では、ext4 と restic を組み合わせ、サーバーが管理しないストレージへ暗号化・重複排除済みのバックアップを書き込めば、メモリを消費せずにほぼ同じ範囲をカバーできます。
障害パターンと表示される文字列
再起動後にプールが消えています。 zpool status を実行すると no pools available が表示されます。インポートサービスは /etc/zfs/zpool.cache を読み込むため、そのファイルにないプールはブート時にインポートされません。sudo zpool import でインポート可能なプールを確認し、sudo zpool import tank で復元し、sudo zpool set cachefile=/etc/zfs/zpool.cache tank で再起動後も維持されるようにします。別のシステムから正常にエクスポートされていないプールでは cannot import 'tank': pool may be in use from other system が表示されます。他のホストがそのプールを使用していないことを確認できた場合は、sudo zpool import -f tank でこの状態を上書きできます。
modprobe: FATAL: Module zfs not found in directory /lib/modules/6.12.0-... がカーネル更新後の Debian で発生します。新しいカーネル用に DKMS がビルドされていません。通常は、対応する headers がインストールされていないことが原因です。dkms status で、どのカーネル用に何がビルドされているかを確認できます。次に sudo apt install -y linux-headers-$(uname -r) で sudo dkms autoinstall を実行して再ビルドし、sudo zpool import tank でプールを復元します。
ファイルを削除したのにプールが満杯です。 スナップショットが削除済みデータを参照している間、そのデータはディスク上に残ります。そのため、du と df の結果が一致しません。zfs list -o space -r tank で使用量を USEDDS と USEDSNAP に分けて確認できます。USEDSNAP が大きければ、それが原因です。sudo zfs destroy tank/data@2026-06-01 で古いスナップショットを破棄すると、空き容量が戻ります。
zpool status の CKSUM カウントが増え続けています。 ZFS の下位にある何かが不正なデータを返しています。ミラーでは、このカウントは警告を示し、ブロックは修復されています。単一ディスクのプールではファイルが失われます。zpool status -v で対象ファイルを確認し、このプールに保存していないバックアップからそのファイルだけを復元します。
サーバーが遅く、スワップが発生しています。 前述の方法で ARC の上限を設定し、arc_summary を実行してヒット率を確認します。作業セットを保持できないほど ARC が小さいと、すべての読み取りがディスクに到達します。その場合は、ページキャッシュを使用する通常のファイルシステムのほうが適しています。
FAQ
ZFS には VPS 上でどの程度の RAM が必要ですか?
ZFS は 2 GB のインスタンスで動作します。重要なのは、アプリケーション用にどれだけの RAM が残るかです。チューニングしない場合、OpenZFS 2.3 では ARC が RAM から 1 GiB を引いた値と RAM の 5/8 の大きい方まで拡張するため、4 GB のサーバーではキャッシュに 3 GiB を割り当てられます。zfs_arc_max をワークロードで使用可能な値に設定し、/proc/spl/kstat/zfs/arcstats から c_max 行を読み取って確認します。
ZFS のスナップショットはバックアップですか?
いいえ。スナップショットはデータと同じプールに保存されます。これは不正な rm やアップグレードの失敗からは保護できますが、プールまたはインスタンスが失われると同時に失われます。zfs send で別のマシンへ送信するか、このサーバーが管理していないストレージへ書き込むバックアップツールを実行して、バックアップに変換してください。
ZFS は FreeBSD と Linux で同じように動作しますか?
2020 年 12 月の OpenZFS 2.0 以降、同じコードベース、同じコマンド、同じディスク上フォーマットを使用しており、プールも相互に移行できます。違いはパッケージングです。FreeBSD では、ZFS はベースシステムに含まれています。Linux では、ディストリビューションごとに異なります。Ubuntu はモジュールをカーネルパッケージに組み込みますが、Debian は DKMS を使用してマシン上でビルドするため、再ビルドが成功するまでカーネルアップグレード後にモジュールが使用できなくなることがあります。
1 台のディスクしかない VPS で、ZFS は破損を修復できますか?
ZFS は破損を検出してファイル名を示しますが、修復はできません。修復にはブロックの 2 つ目のコピーが必要だからです。データセットで zfs set copies=2 を有効にすると、容量を 2 倍使用してその 2 つ目のコピーを作成できます。これにより不良ブロックには対処できますが、ボリュームの消失には対処できません。実際に修復機能を提供するのは、2 つのボリュームにまたがるミラーです。
圧縮によってサーバーの速度は低下しますか?
lz4 によって、通常は高速になります。圧縮されたブロックでは書き込むバイト数と読み取るバイト数が減り、ブロックあたりの CPU 負荷も、削減できるディスク I/O と比べて小さいためです。プールのルートで compression=lz4 を設定すると、すべてのデータセットが継承します。実際のデータを書き込んだ後に zfs get compressratio tank を確認してください。