ZFS
ZFS は (現在は Oracle によって吸収合併された) Sun Microsystems によって作成された先進的なファイルシステムで、2005年11月に OpenSolaris でリリースされました。ZFS には以下の機能があります: ストレージプール (統合ボリューム管理 -- zpool), Copy-on-write, スナップショット, データ整合性のチェックと自動修復 (スクラブ), RAID-Z, 最大16エクサバイトのファイルサイズ、最大256ゼタバイトのボリュームサイズ。ファイルシステム (データセット) やファイルの数は無制限です [1]。ZFS は Common Development and Distribution License (CDDL) でライセンスされています。
"The last word in filesystems" では ZFS は安定していて高速、セキュアで、そして将来性を考えた設計をしていると述べられています。ライセンスが CDDL で、GPL と互換がないため、ZFS は Linux カーネルと一緒に配布することができません。しかしながら、サードパーティによってネイティブの Linux カーネルモジュールを開発・配布することは可能です。それが ZFSonLinux (ZOL) になります。
ZOL はローレンス・リバモア国立研究所による後押しを受けているプロジェクトで、その大規模なストレージ要件とスーパーコンピュータに合うようなネイティブの Linux カーネルモジュールを開発することを目標としています。
目次
- 1 インストール
- 2 ZFS の実験
- 3 設定
- 4 ストレージプールの作成
- 5 チューニング
- 6 使用方法
- 7 トラブルシューティング
- 7.1 ZPool の作成が失敗する
- 7.2 ZFS の使用 RAM が多すぎる
- 7.3 Does not contain an EFI label
- 7.4 No hostid found
- 7.5 SAS/SCSI デバイスからの起動中にプールが見つかりません
- 7.6 起動時に zfs プールがマウントされない: "pool may be in use from other system"
- 7.7 デバイスのセクタアライメントが異なっている
- 7.8 プールの再同期が停止/再起動/遅いですか?
- 7.9 initramfs zpool.cache 内の使用できないプールのインポートの失敗によって引き起こされる起動の遅さを修正しました。
- 7.10 ZFS コマンド履歴
- 8 ヒントとテクニック
- 9 参照
インストール
一般
Arch User Repository または archzfs リポジトリから以下のパッケージのどれかをインストールしてください:
- zfs-linuxAUR - 安定版のリリース [3]。
- zfs-linux-gitAUR - 開発版のリリース (新しいバージョンのカーネルをサポート) [4]。
- zfs-linux-ltsAUR - LTS カーネル用の安定版リリース。
- zfs-linux-lts-gitAUR - LTS カーネル用の 開発版 リリース
- zfs-linux-hardenedAUR - hardened カーネル用の安定版リリース。
- zfs-linux-hardened-gitAUR - hardened カーネル用の 開発版 リリース。
- zfs-linux-zenAUR - zen カーネル用の安定版リリース。
- zfs-linux-zen-gitAUR - zen カーネル用の 開発版 リリース。
- zfs-dkmsAUR - ダイナミックカーネルモジュールをサポートしているバージョン。
- zfs-dkms-gitAUR - ダイナミックカーネルモジュールをサポートしている 開発版 リリース。
上記のパッケージにはそれぞれ zfs-utils
, spl
, spl-utils
パッケージに依存しています。SPL (Solaris Porting Layer) は ZFS を使用するために Solaris の API を実装する Linux カーネルモジュールです。
パッケージをインストールしたらコマンドラインで zpool status
を実行してテストしてください。"insmod" エラーが表示される場合、depmod -a
を試してみてください。
Root on ZFS
こちらを参照 ZFS に Arch Linux をインストール#インストール
DKMS
ユーザーは DKMS を利用して、カーネルのアップグレードごとに ZFS モジュールを自動的に再構築できます。
zfs-dkmsAUR または zfs-dkms-gitAUR をインストールします。
ZFS の実験
~/zfs0.img
~/zfs1.img
~/zfs2.img
などのシンプルなファイルの仮想ブロックデバイス (ZFS では VDEV と呼称) を使って、データを消失する危険性なく、ZFS の実験を行いたいユーザーは ZFS/仮想ディスクの記事を見て下さい。RAIDZ アレイの作成や、意図的にデータを破損させてそれを復元したり、データセットのスナップショットなどの一般的な作業を取り扱っています。
設定
ZFS は、その作成者によって "管理不要" のファイルシステムとみなされています。したがって、ZFS の構成は非常に簡単です。設定は主に、zfs
と zpool
の 2 つのコマンドで行われます。
自動起動
ZFS を"ゼロアドミニストレーション"の名に負うように使うには、zfs デーモンを起動時にロードする必要があります。このため /etc/fstab
で zpool をマウントする必要はありません。zfs デーモンが自動的に zfs プールをインポートしてマウントを行います。デーモンは /etc/zfs/zpool.cache
ファイルを読み込んで zfs プールをマウントします。
zfs デーモンによって自動でマウントしたいプール毎に次を実行:
# zpool set cachefile=/etc/zfs/zpool.cache <pool>
関連するサービスを 有効化 (zfs-import-cache.service
) とターゲット (zfs.target
および zfs-import.target
) プールは起動時に自動的にインポートされます。
ZFS ファイルシステムをマウントするには、次の 2 つの選択肢があります。
- zfs-mount.service を有効にします
- zfs-mount-generator を使用する
zfs-mount.service の使用
起動時に ZFS ファイルシステムを自動的にマウントするには、zfs-mount.service
と zfs.target
を 有効化 する必要があります。
zfs-mount-generator の使用
zfs-mount-generator を使用して、起動時に ZFS ファイルシステムの systemd マウント ユニットを作成することもできます。systemd は、zfs-mount.service
を使用せずに、マウント ユニットに基づいてファイルシステムを自動的にマウントします。そのためには、次のことを行う必要があります。
/etc/zfs/zfs-list.cache
ディレクトリを作成します。- マウント可能な ZFS ファイルシステムのリストを作成するために必要な ZFS イベント デーモン (ZED) スクリプト (ZEDLET と呼ばれる) を有効にします。(このリンクは、OpenZFS 2.0.0 以上を使用している場合に自動的に作成されます。)
# ln -s /usr/lib/zfs/zed.d/history_event-zfs-list-cacher.sh /etc/zfs /zed.d
- 有効化
zfs.target
および 起動/有効化 ZFS イベントデーモン (zfs-zed.service
) このサービスは、前のステップでスクリプトを実行する役割を果たします。 /etc/zfs/zfs-list.cache
にプールにちなんだ名前の空のファイルを作成する必要があります。ZEDLET は、プールのファイルがすでに存在する場合にのみファイルシステムのリストを更新します。# touch /etc/zfs/zfs-list.cache/<プール名>
/etc/zfs/zfs-list.cache/<プール名>
の内容を確認します。空の場合は、zfs-zed.service
が実行されていることを確認し、次を実行して ZFS ファイルシステムのいずれかの canmount プロパティを変更します: {{bc|1=zfs set canmount=off zroot/この変更により、ZFS は ZED によってキャプチャされるイベントを発生させ、ZEDLET を実行して/etc/zfs/zfs-list.cache
内のファイルを更新します。/etc/zfs/zfs-list.cache
内のファイルが更新された場合は、次のコマンドを実行してファイルシステムのcanmount
プロパティを設定し直すことができます:zfs set canmount=on zroot/fs1
システム内の ZFS プールごとに、/etc/zfs/zfs-list.cache
にファイルを追加する必要があります。zfs-import-cache.service
と zfs-import.target
を 上で説明 として有効にして、プールがインポートされていることを確認します。
ストレージプールの作成
利用できるドライブの一覧を見るには # parted --list
を使います。zfs ファイルシステムを作成する前にドライブをパーティションする必要はありません、推奨もされていません。
ドライブの一覧を確認できたら、次は zpool を追加するドライブの id を取得します。10デバイス以下の ZFS ストレージプールを作成する際はデバイス id を使うことを zfs on Linux の開発者は推奨しています。id を調べるには:
# ls -lh /dev/disk/by-id/
id は以下のように表示されます:
lrwxrwxrwx 1 root root 9 Aug 12 16:26 ata-ST3000DM001-9YN166_S1F0JKRR -> ../../sdc lrwxrwxrwx 1 root root 9 Aug 12 16:26 ata-ST3000DM001-9YN166_S1F0JTM1 -> ../../sde lrwxrwxrwx 1 root root 9 Aug 12 16:26 ata-ST3000DM001-9YN166_S1F0KBP8 -> ../../sdd lrwxrwxrwx 1 root root 9 Aug 12 16:26 ata-ST3000DM001-9YN166_S1F0KDGY -> ../../sdb
そして、いよいよ ZFS プールを作成します:
# zpool create -f -m <mount> <pool> raidz <ids>
- create: プールを作成するサブコマンド。
- -f: 強制的にプールを作成する。"EFI label error" を無視します。#Does not contain an EFI label を見て下さい。
- -m: プールのマウントポイント。指定されない場合、プールは
/<pool>
にマウントされます。
- pool: プールの名前。
- raidz: デバイスのプールから作成される仮想デバイスのタイプ。Raidz は raid5 の特殊な実装です。raiz に関する詳細は Jeff Bonwick's Blog -- RAID-Z を見て下さい。RAID-1 を使用する場合は代わりに mirror を使用したほうが良いでしょう [5]。
- ids: プールに含まれるドライブまたはパーティションの名前。
/dev/disk/by-id
で取得。
完全なコマンドは以下のようになります:
# zpool create -f -m /mnt/data bigdata raidz ata-ST3000DM001-9YN166_S1F0KDGY ata-ST3000DM001-9YN166_S1F0JKRR ata-ST3000DM001-9YN166_S1F0KBP8 ata-ST3000DM001-9YN166_S1F0JTM1
Advanced Format ディスク
セクターサイズが512バイトではなく4096バイトの Advanced Format ディスクを使用する場合、レガシーなシステムとの後方互換性のため ZFS のセクターサイズ自動検出アルゴリズムが512バイトと検出して、パフォーマンスが落ちてしまうことがあります。正しいセクターサイズが使われるように、ashift=12
オプションを使用して下さい (ZFS on Linux FAQ を参照)。この場合の完全なコマンドは以下の通りになります:
# zpool create -f -o ashift=12 -m /mnt/data bigdata raidz ata-ST3000DM001-9YN166_S1F0KDGY ata-ST3000DM001-9YN166_S1F0JKRR ata-ST3000DM001-9YN166_S1F0KBP8 ata-ST3000DM001-9YN166_S1F0JTM1
プールの作成の確認
コマンドが成功しても、何も出力はされません。$ mount
コマンドを使うことでプールがマウントされているかどうか表示できます。# zpool status
を使えばプールが作成されたか表示されます。
# zpool status
pool: bigdata state: ONLINE scan: none requested config: NAME STATE READ WRITE CKSUM bigdata ONLINE 0 0 0 -0 ONLINE 0 0 0 ata-ST3000DM001-9YN166_S1F0KDGY-part1 ONLINE 0 0 0 ata-ST3000DM001-9YN166_S1F0JKRR-part1 ONLINE 0 0 0 ata-ST3000DM001-9YN166_S1F0KBP8-part1 ONLINE 0 0 0 ata-ST3000DM001-9YN166_S1F0JTM1-part1 ONLINE 0 0 0 errors: No known data errors
この段階で、起動時に ZFS プールがマウントされるか確認するためにマシンを再起動すると良いでしょう。データを移し替える前に全てのエラーに対処するのがベストです。
GRUB 互換のプールを作成する
zpool はプールの全ての機能を有効にします。/boot
を ZFS 上に配置して GRUB を使用する場合、GRUB によってサポートされている機能だけを有効にしてください。そうしないと GRUB がプールを読み込むことができなくなります。GRUB 2.02 は lz4_compress
, hole_birth
, embedded_data
, extensible_dataset
, large_blocks
をサポートしています。これは ZFSonLinux 0.7.1 の全ての機能ではないため、サポートされていない機能は無効化する必要があります。
未対応の機能を無効化してプールを作成するには:
# zpool create -o feature@multi_vdev_crash_dump=disabled \ -o feature@large_dnode=disabled \ -o feature@sha512=disabled \ -o feature@skein=disabled \ -o feature@edonr=disabled \ $POOL_NAME $VDEVS
ZFS on Linux の git 版を使う場合は -o feature@encryption=disabled
も追加してください。
チューニング
一般
zfs ファイルシステムでは多数のパラメータを使うことができます。パラメータの完全なリストは zfs get all <pool>
で見ることが可能です。調整するパラメータとしては atime と compression が一般的です。
atime はデフォルトで有効にされていますが、ほとんどのユーザーにとっては zpool に余分な書き込みになります。zfs コマンドを使うことで atime を無効にできます:
# zfs set atime=off <pool>
atime を完全にオフにする代わりとして、relatime を使うこともできます。ext4/xfs のデフォルトの atime の処理と同じで、変更日時が更新されたとき、または24時間で一度もアクセス日時が更新されなかった場合にのみ、ファイルのアクセス日時が更新されます。atime=off と atime=on の折衷案になります。このプロパティは atime が on になっているときだけ適用されます:
# zfs set relatime=on <pool>
compression はつまり、データの透過圧縮です。ZFS は様々なアルゴリズムに対応しており、現在は lz4 はデフォルトです。あまり書き込みを行わないようなデータなら gzip を有効にすることで高い圧縮率を実現できます。詳しくは man ページを読んでください。zfs コマンドを使って圧縮を有効にするには:
# zfs set compression=lz4 <pool>
また、zfs コマンドを使うことで zfs の他のオプションを表示できます:
# zfs get all <pool>
SSD キャッシュ
SSD デバイスを書き込みインテントログ (ZIL または SLOG) として追加して l2arc (layer 2 adaptive replacement cache) として使うことができます。手順は新しい VDEV を作成するのと似ています。以下のコマンドで使用する <device-id> は ls -lh /dev/disk/by-id/
で確認できます。
ZIL を追加するには:
# zpool add <pool> log <device-id>
またはミラー ZIL を追加するには:
# zpool add <pool> log mirror <device-id-1> <device-id-2>
l2arc を追加するには:
# zpool add <pool> cache <device-id>
またはミラー l2arc を追加するには:
# zpool add <pool> cache mirror <device-id-1> <device-id-2>
データベース
ZFS は他のファイルシステムとは異なり、(一般的にはブロックサイズと呼ばれる) レコードサイズを変えることができます。デフォルトでは、ZFS のレコードサイズは 128KiB で、書き込むファイルのサイズにあわせて 512B から 128KiB までのサイズのブロックを動的に割り当てます。数バイトの書き込みの時でも新規に 128KiB のブロックを割り当てなくてはならないという代償を払って、断片化やファイルアクセスが補助されます。
ほとんどの RDBMS はデフォルトで 8KiB サイズのブロックで動作します。MySQL/MariaDB, PostgreSQL, Oracle のブロックサイズは調整することできますが、デフォルトのブロックサイズは3つとも 8KiB を使っています。パフォーマンスの影響を考え、また、(バックアップ用の) スナップショットの差異を最小限にするために、以下のようなコマンドを使って ZFS をデータベースに適応するよう設定するのが望ましいでしょう:
# zfs set recordsize=8K <pool>/postgres
これらの RDBMS にはそれぞれ独自のキャッシュアルゴリズムが実装されており、大抵は ZFS の ARC と同じようなメカニズムです。メモリの節約の観点から、ZFS によるデータベースのファイルデータのキャッシュを無効にして、キャッシュについてはデータベースに任せるのが良いでしょう:
# zfs set primarycache=metadata <pool>/postgres
プールにログデバイスが設定されていない場合、ZFS はインテントログ (ZIL) のためにプールのデータディスク上に領域を取っておきます。ZFS はクラッシュからのリカバリの際にこのスペースを使いますが、データベースは大抵トランザクションがコミットされるたびにデータファイルをファイルシステムに同期させます。この結果 ZFS が二回データをデータディスクに引き渡すことになるので、パフォーマンスにかなり影響が出てしまう可能性があります。ZFS が ZIL を使わないように設定することができ、この場合は、データがファイルシステムに渡されるのは一度だけになります。データベース以外のファイルシステムや、ログデバイスが設定されているプールでこの設定を行うと、逆にパフォーマンスが下がってしまうことになるので、注意してください:
# zfs set logbias=throughput <pool>/postgres
ファイルシステムの作成時に以上の設定を行うこともできます、例えば:
# zfs create -o recordsize=8K \ -o primarycache=metadata \ -o mountpoint=/var/lib/postgres \ -o logbias=throughput \ <pool>/postgres
/tmp
ZFS を使って /tmp
ディレクトリを保存したい場合、ファイルシステムの同期を無効にすることで /tmp
への書き込みを行うアプリケーションのパフォーマンスを向上させることがあります。これによって ZFS はアプリケーションの同期リクエスト (例: fsync
や O_SYNC
) を無視して、すぐに戻るようになります。アプリケーションサイドのデータの一貫性を保つのが難しくなる一方 (データベースで同期を無効化してはいけません)、/tmp
のファイルはあまり重要でないことが多いため、影響は限られます。ZFS 自体の整合性には影響を与えないので注意してください。アプリケーションがディスク上にあると期待しているデータが実際に書きだされなくてクラッシュが起こる可能性があるくらいです。
# zfs set sync=disabled <pool>/tmp
さらに、セキュリティ上の理由で、/tmp
ファイルシステムの setuid と devices を無効化すると良いでしょう。特権昇格攻撃やデバイスノードの使用をふせぐことができます:
# zfs set setuid=off <pool>/tmp # zfs set devices=off <pool>/tmp
上記の全てをまとめると create コマンドは以下のようになります:
# zfs create -o setuid=off -o devices=off -o sync=disabled -o mountpoint=/tmp <pool>/tmp
また、ZFS に /tmp
を配置するときは、systemd の tmpfs による自動的な /tmp
をマスク (無効化) する必要があるので注意してください。そうしないと ZFS が起動時やインポート時にデータセットをマウントできなくなってしまいます:
# systemctl mask tmp.mount
zvol
zvol は RDBMS と同じようにブロックサイズ関連の問題を被りますが、zvol のデフォルトの recordsize は始めから 8KiB になっているので大丈夫です。可能であれば、zvol に含まれているパーティションは recordsize にあわせて (fdisk と gdisk の最新版ではデフォルトで 1MiB セグメントに合わせます)、ファイルシステムのブロックサイズも同じサイズに合わせるのがベストです。それ以外にも、必要に応じて recordsize を zvol 内のデータに適合させることもできます (ほとんどのファイルシステムでは 8KiB で十分ですが、4KiB のブロックを使用した方が良いときもあります)。
RAIDZ と Advanced Format 物理ディスク
zvol の各ブロックにはそれぞれパリティディスクが存在しており、もし、論理ブロックサイズが 4096B, 8192B などの物理メディアを使用していて、パリティを物理ブロック全体に保存する必要がある場合、zvol に必要な容量が劇的に増えてしまう可能性があります。zvol の論理容量の2倍位上の物理ストレージ容量が必要になります。recordsize を 16k や 32k に設定することでこの必要容量をかなり減らすことができるかもしれません。
詳しくは ZFS on Linux issue #1807 を参照。
使用方法
zpool の下に手動でディレクトリを作成するのに対して、任意で zpool の下にデータセットを作成することができます。データセットはスナップショットに加えて制御のレベルを増加させます (クォータなど)。データセットの作成とマウントをするときは、同じ名前のディレクトリが zpool に存在してはいけません。データセットを作成するには、次を使用:
# zfs create <nameofzpool>/<nameofdataset>
データセットには ZFS の特定属性を適用させることができます。例えば、データセット内の特定のディレクトリにクォータ制限をかけることが可能です:
# zfs set quota=20G <nameofzpool>/<nameofdataset>/<directory>
ZFS で利用できるコマンドを全て表示するには、次のコマンドを使用:
$ man zfs
または:
$ man zpool
ネイティブ暗号化
ZFS のネイティブ暗号化は 0.7.0.r26 以上のバージョンから使うことができ zfs-linux-gitAUR, zfs-dkms-gitAUR などの開発ビルドのパッケージで利用できます。バージョン 0.7 はリリースされていますが、0.7.3 現在、安定版では機能は有効になっていないために開発ビルドが必要になります。/usr/src/zfs-*/include/sys/fs/zfs.h
の ZFS_PROP_ENCRYPTION
の定義をチェックすることで、インストールしている zfs で暗号化が使えるかどうか確認できます。
- サポートされている暗号化オプション:
aes-128-ccm
,aes-192-ccm
,aes-256-ccm
,aes-128-gcm
,aes-192-gcm
,aes-256-gcm
。暗号化がon
に設定されている場合、aes-256-ccm
が使われます。 - サポートされているキーフォーマット:
passphrase
,raw
,hex
。
-o pbkdf2iters <n>
で PBKDF2 の繰り返しを指定することもできます (キーの復号化に時間がかかるようになります)。
パスフレーズによるネイティブ暗号化を有効にしてデータセットを作成するには:
# zfs create -o encryption=on -o keyformat=passphrase <nameofzpool>/<nameofdataset>
パスフレーズの代わりにキーを使うには:
# dd if=/dev/urandom of=/path/to/key bs=1 count=32 # zfs create -o encryption=on -o keyformat=raw -o keylocation=file:///path/to/key <nameofzpool>/<nameofdataset>
手動でキーをロードしてから暗号化されたデータセットをマウントすることも可能です:
# zfs load-key <nameofzpool>/<nameofdataset> # load key for a specific dataset # zfs load-key -a # load all keys # zfs load-key -r zpool/dataset # load all keys in a dataset
暗号化されたデータセットを含むプールをインポートすると、ZFS はデフォルトではデータセットを復号化しません。復号化するには -l
を使います:
# zpool import -l pool
systemd カスタムユニットを使うことで起動時に復号化を自動的に行うことができます。例:
/etc/systemd/system/zfs-key@.service
[Unit] Description=Load storage encryption keys Before=systemd-user-sessions.service Before=zfs-mount.service [Service] Type=oneshot RemainAfterExit=yes ExecStart=/usr/bin/bash -c '/usr/bin/zfs load-key zpool/%i <<< $(systemd-ask-password "Encrypted storage password (%i): ")' [Install] WantedBy=zfs-mount.service
暗号化ボリュームを指定してサービスインスタンスを有効化してください: # systemctl enable zfs-key@dataset
。
systemd-user-sessions.service
の Before=
によってローカル IO デバイスがシステム UI に移る前に systemd-ask-password
が呼び出されます。
スクラブ
少なくとも週に一度は ZFS プールをスクラブするべきです。プールをスクラブするには:
# zpool scrub <pool>
週一で自動的にスクラブするようにするには、root の crontab に次の行を設定してください:
# crontab -e
... 30 19 * * 5 zpool scrub <pool> ...
<pool>
は ZFS プールの名前に置き換えて下さい。
zfs プールの状態を確認
読み書きエラーなどの情報を含む、ZFS プールの統計が書かれた表を表示するには、次を使用:
# zpool status -v
ストレージプールを破壊
ZFS ではマウントされているストレージプールを破壊して、ZFS デバイスに関する全てのメタデータを簡単に削除することができます。次のコマンドはプールに含まれているデータを全て破壊します:
# zpool destroy <pool>
状態を確認すると:
# zpool status
no pools available
プールの名前を確認するには、#zfs プールの状態を確認 を見て下さい。
ストレージプールをエクスポート
ストレージプールを他のシステムで使用するときは、まずエクスポートする必要があります。また、archiso からプールをインポートしたときも、archiso での hostid と起動環境での hostid が異なるのでプールをエクスポートしなくてはなりません。zpool コマンドはエクスポートされていないストレージプールのインポートを拒否します。-f
引数を使って強制的にインポートすることもできますが、良い手段とは言えません。
エクスポートされていないストレージプールをインポートするとストレージプールが他のシステムによって使用されているというエラーが発生します。このエラーは起動時に発生することがあり、busybox コンソールでシステムが突然停止して、archiso による応急処置が必要になります。プールをエクスポートするか、またはカーネルのブートパラメータに zfs_force=1
を追加してください (こちらの方法はあまり芳しくありません)。#起動時に zfs プールがマウントされない: "pool may be in use from other system" を参照。
プールをエクスポートするには:
# zpool export <pool>
Zpool の名前を変更
既に作成済みの zpool の名前の変更は2ステップで行います:
# zpool export oldname # zpool import oldname newname
別のマウントポイントを設定
指定の zpool のマウントポイントは一つのコマンドで随意に移動することができます:
# zfs set mountpoint=/foo/bar poolname
アクセス制御リスト
ZFS プールで ACL を使うには:
# zfs set acltype=posixacl <nameofzpool>/<nameofdataset> # zfs set xattr=sa <nameofzpool>/<nameofdataset>
パフォーマンス上の理由から xattr
を設定することが推奨されています [6]。
スワップボリューム
ZFS ではスワップファイルを使うことはできませんが、ユーザーは ZFS ボリューム (ZVOL) をスワップとして利用することができます。ZVOL のブロックサイズをシステムページサイズと一致するように設定するのが重要です。システムページサイズは getconf PAGESIZE
コマンドで取得することができます (x86_64 でのデフォルトは 4KiB)。また、メモリが少ないシチュエーションでシステムを上手く動作させ続けるには zvol データのキャッシュを行わないほうが良いでしょう。
8 GiB の zfs ボリュームを作成:
# zfs create -V 8G -b $(getconf PAGESIZE) \ -o logbias=throughput -o sync=always\ -o primarycache=metadata \ -o com.sun:auto-snapshot=false <pool>/swap
スワップパーティションとして設定:
# mkswap -f /dev/zvol/<pool>/swap # swapon /dev/zvol/<pool>/swap
この設定を永続化させるには、/etc/fstab
を編集します。ZVOL は discard をサポートしており、ZFS のブロックアロケータの役に立ったり、スワップが満杯になったときに他のデータセットにおける断片化を減らすことができます。
/etc/fstab
に次の行を追加:
/dev/zvol/<pool>/swap none swap discard 0 0
ハイバネートフックはファイルシステムよりも前にロードされる必要があり、ZVOL をスワップとして使うとハイバネート機能が使えなくなることを覚えておいて下さい。ハイバネートが必要な場合は、スワップ用のパーティションを取っておいて下さい。
自動スナップショット
Linux の ZFS 自動スナップショットサービス
AUR の zfs-auto-snapshot-gitAUR パッケージにはスナップショットの管理の自動化を行うシェルスクリプトが入っています。スナップショットには日付とラベルで名前が付けられ (1時間毎、1日毎など)、全ての ZFS のデータセットを素早く簡単にスナップショットできます。15分毎・1時間毎・1日毎・1週間毎・1ヶ月毎にスナップショットを作成する cron タスクもインストールされます。任意で --keep パラメータを調整することでスナップショットを保存する期間を設定できます (1ヶ月毎のスクリプトはデフォルトで1年間までデータを保存します)。
データセットがスナップショットされないようにするには、データセットに com.sun:auto-snapshot=false
を設定してください。同じように、ラベルで細かい設定をすることができます。例えば、1ヶ月毎のスナップショットを作成しないようにするには com.sun:auto-snapshot:monthly=false
を設定します。
ZFS スナップショットマネージャ
AUR の zfs-snap-managerAUR パッケージは ZFS データセットのスナップショットを毎日作成して "Grandfather-father-son" 方式で削除していく python サービスを提供します。7日毎、5週間毎、3ヶ月毎、2年間毎などのスナップショットを保持するよう設定できます。
このパッケージは ZFS が動作している他のマシンへのレプリケーションもサポートしており zfs send
と zfs receive
を使います。同期先のマシンでもこのパッケージを使用している場合、複製したスナップショットを長期間にわたって保持するように設定することが可能です。これによって、同期元のマシンには毎日のスナップショットだけを少しだけローカルに保存して、リモートのストレージサーバーに大量のスナップショットを保存するという構成ができます。
トラブルシューティング
ZPool の作成が失敗する
以下のエラーが発生した場合:
# the kernel failed to rescan the partition table: 16 # cannot label 'sdc': try using parted(8) and then provide a specific slice: -1
ZFS がプールの作成が1秒未満で終わることを要求しているのが原因の一つです。通常状態では問題ありませんが、1秒以上かかってしまう状況というのはたくさんあります。もう一度作成を試行する前に、それぞれのドライブをクリアにする必要があります。
# parted /dev/sda rm 1 # parted /dev/sda rm 1 # dd if=/dev/zero of=/dev/sdb bs=512 count=1 # zpool labelclear /dev/sda
力づくで何度も作成してみることもでき、運が良ければ ZPool の作成が1秒未満で終わるでしょう。作成のスローダウンが一度発生すると、ドライブのバースト読み書きが遅くなることがあります。ZPool の作成と並行して読み込むことで、バースト速度を向上させることが可能です。
# dd if=/dev/sda of=/dev/null
複数のディスクで行うには、上記のコマンドをそれぞれのディスクでファイルに保存して次を実行:
# cat $FILE | parallel
そして同時に ZPool の作成を実行します。
ZFS の使用 RAM が多すぎる
デフォルトでは、ZFS はホストのシステムメモリの3分の2まで使用してファイル操作をキャッシュします (ARC)。ZFS はエンタープライズクラスのストレージシステム用に設計されたことを思い出して下さい。ARC サイズを調整するには、以下をカーネルパラメータのリストに追加します:
zfs.zfs_arc_max=536870912 # (for 512MB)
他の設定オプションや、より詳しい説明は gentoo-wiki:zfs#arc を見て下さい。
Does not contain an EFI label
zfs ファイルシステムを作成しようとするときに以下のエラーが発生することがあります:
/dev/disk/by-id/<id> does not contain an EFI label but it may contain partition
このエラーを打破するには zfs の create コマンドで -f
を使って下さい。
No hostid found
起動時に initscript の出力が表示される前に以下のエラーが発生する場合:
ZFS: No hostid found on kernel command line or /etc/hostid.
この警告は ZFS モジュールが spl hosted にアクセスできないのが原因です。この問題には2つの解決方法があります。一つはブートローダーのカーネルパラメータに spl hostid を記述することです。例えば、spl.spl_hostid=0x00bab10c
を追加します。
もう一つの解決方法は /etc/hostid
に hostid があることを確認して、initramfs イメージを再生成することです。それによって hostid 情報が initramfs イメージにコピーされます。
# mkinitcpio -p linux
SAS/SCSI デバイスからの起動中にプールが見つかりません
SAS/SCSI ベースでブートしている場合、ブートしようとしているプールが見つからないというブートの問題が発生することがあります。この原因として考えられるのは、デバイスの初期化がプロセスの中で遅すぎることです。これは、zfs がプールを組み立てようとする時点でデバイスを見つけることができないことを意味します。
この場合、続行する前に、デバイスがオンラインになるまで SCSI ドライバーを強制的に待機させる必要があります。これを /etc/modprobe.d/zfs.conf
に記述します。
/etc/modprobe.d/zfs.conf
options scsi_mod scan=sync
その後、initramfs を再生成
これが機能するのは、zfs フックが /etc/modprobe.d/zfs.conf
にあるファイルを initcpio にコピーし、ビルド時に使用されるためです。
起動時に zfs プールがマウントされない: "pool may be in use from other system"
プールがエクスポートされていない
zpool がインポートできないために新しいインストール環境が起動しない場合、インストール環境に chroot して zpool を正しくエクスポートしてください。#archzfs による chroot の応急処置 を参照。
chroot 環境に入ったら、ZFS モジュールをロードして強制的に zpool をインポートします:
# zpool import -a -f
そしてプールをエクスポートします:
# zpool export <pool>
利用可能なプールを確認するには、次を使用:
# zpool status
ZFS は hostid を使って zpool が作成されたシステムを追跡するのでプールをエクスポートする必要があります。hostid はネットワークの設定時に生成されます。archiso でのインストール中、ネットワーク設定が違うせいで新しい環境に含まれている hostid と異なる hostid が生成されることがあります。zfs ファイルシステムをエクスポートしたら新しい環境でインポートしなおしてください。それで hostid はリセットされます。参照: Re: Howto zpool import/export automatically? - msg#00227。
起動する度に ZFS が "pool may be in use" と表示する場合は、上記のようにプールを適切にエクスポートして、通常通りに ramdisk を再生成してください:
# mkinitcpio -p linux
hostid が間違っている
プールが正しくエクスポートされていることを確認してください。zpool をエクスポートすると所有者を示す hostid がクリアされます。そのため最初の起動時に zpool を正しくマウントする必要があります。マウントされなかった場合、他の問題が起こります。
hostid が正しく設定されておらず zfs が混同されているために zfs プールがマウントできないときは、もう一度再起動してください。手動で zfs に適切な数字を指定します。hostid は再起動しても変わらないため zpool は適切にマウントされます。
zfs_force を使って起動して hostid をメモします。例:
% hostid 0a0af0f8
この数字を spl.spl_hostid=0x0a0af0f8
のようにして カーネルパラメータ に追加してください。もう一つの解決方法は hostid を initram イメージの中に書き出すことです。この方法については インストールガイド の説明を見て下さい。
カーネルパラメータ に zfs_force=1
を追加することでチェックを常に無視することができます。ただし恒久的に使用するのは推奨されません。
デバイスのセクタアライメントが異なっている
ドライブが故障したときは、できるだけはやく同じドライブでドライブを交換してください。
# zpool replace bigdata ata-ST3000DM001-9YN166_S1F0KDGY ata-ST3000DM001-1CH166_W1F478BD -f
ただし、この場合、以下のエラーが発生します:
cannot replace ata-ST3000DM001-9YN166_S1F0KDGY with ata-ST3000DM001-1CH166_W1F478BD: devices have different sector alignment
ZFS は ashift オプションを使って物理ブロックサイズを調整しています。故障したディスクを置き換えるとき、ZFS は ashift=12
を使用しますが、故障したディスクの ashift が異なっている (例えば ashift=9
) 場合、結果としてこのエラーが起こってしまいます。
ブロックサイズが 4KB の Advanced Format ディスクの場合、一番良いパフォーマンスを出すため ashift は 12 が推奨されます。1.10 What’s going on with performance? や ZFS and Advanced Format disks を見て下さい。
zpool の ashift を確認するには zdb を使います: zdb | grep ashift
。
-o
引数を使って交換用ドライブの ashift を設定してください:
# zpool replace bigdata ata-ST3000DM001-9YN166_S1F0KDGY ata-ST3000DM001-1CH166_W1F478BD -o ashift=9 -f
zpool status で確認を行なって下さい:
# zpool status -v
pool: bigdata state: DEGRADED status: One or more devices is currently being resilvered. The pool will continue to function, possibly in a degraded state. action: Wait for the resilver to complete. scan: resilver in progress since Mon Jun 16 11:16:28 2014 10.3G scanned out of 5.90T at 81.7M/s, 20h59m to go 2.57G resilvered, 0.17% done config: NAME STATE READ WRITE CKSUM bigdata DEGRADED 0 0 0 raidz1-0 DEGRADED 0 0 0 replacing-0 OFFLINE 0 0 0 ata-ST3000DM001-9YN166_S1F0KDGY OFFLINE 0 0 0 ata-ST3000DM001-1CH166_W1F478BD ONLINE 0 0 0 (resilvering) ata-ST3000DM001-9YN166_S1F0JKRR ONLINE 0 0 0 ata-ST3000DM001-9YN166_S1F0KBP8 ONLINE 0 0 0 ata-ST3000DM001-9YN166_S1F0JTM1 ONLINE 0 0 0 errors: No known data errors
プールの再同期が停止/再起動/遅いですか?
ZFSonLinux github によると、これは 2012 年以降の ZFS-ZED の既知の問題で、再同期化プロセスが常に再起動し、場合によってはスタックし、一部のハードウェアでは一般的に遅くなります。最も簡単な軽減策は、再同期が完了するまで zfs-zed.service を停止することです。
initramfs zpool.cache 内の使用できないプールのインポートの失敗によって引き起こされる起動の遅さを修正しました。
永続的に接続されていない追加のプールがインポートされているときに intramfs を更新すると (カーネル更新の実行時など)、起動時間が大幅に影響を受ける可能性があります。これは、これらのプールが initramfs zpool.cache に追加され、ZFS がこれらのプールをインポートしようとするためです。エクスポートしたり、通常の zpool.cache から削除したりしたかどうかに関係なく、ブートごとに追加のプールが作成されます。
ZFS が起動時に使用できないプールをインポートしようとしていることに気付いた場合は、まず次のコマンドを実行します。
$ zdb -C
起動時にインポートしたくないプールがないか zpool.cache を確認します。このコマンドで、現在使用できない追加のプールが表示される場合は、次のコマンドを実行します。
# zpool set cachefile=/etc/zfs/zpool.cache zroot
zroot という名前のプール以外のプールの zpool.cache をクリアします。場合によっては、zpool.cache を更新する必要がなく、代わりに initramfs を再生成 するだけで済みます。
ZFS コマンド履歴
ZFS は、プールの構造への変更を、実行されたコマンドのログとしてリングバッファーにネイティブに記録します (これをオフにすることはできません) ログは、劣化したプールまたは障害が発生したプールを復元するときに役立つ場合があります。
# zpool history zpool
History for 'zpool': 2023-02-19.16:28:44 zpool create zpool raidz1 /scratch/disk_1.img /scratch/disk_2.img /scratch/disk_3.img 2023-02-19.16:31:29 zfs set compression=lz4 zpool 2023-02-19.16:41:45 zpool scrub zpool 2023-02-19.17:00:57 zpool replace zpool /scratch/disk_1.img /scratch/bigger_disk_1.img 2023-02-19.17:01:34 zpool scrub zpool 2023-02-19.17:01:42 zpool replace zpool /scratch/disk_2.img /scratch/bigger_disk_2.img 2023-02-19.17:01:46 zpool replace zpool /scratch/disk_3.img /scratch/bigger_disk_3.img
ヒントとテクニック
archzfs パッケージを archiso に埋め込む
必要なソフトウェアが含まれるインストールメディアを作成するのは良い考えです。ただし、最新の archiso インストールメディアを CD や USB キーに書き込む必要があります。
既存の環境から、archiso に zfs
を埋め込むには、archiso
パッケージをダウンロード:
# pacman -S archiso
プロセスを開始:
# cp -r /usr/share/archiso/configs/releng /root/media
packages.x86_64
ファイルを編集して以下の行を追加:
spl-utils-linux-git spl-linux-git zfs-utils-linux-git zfs-linux-git
pacman.conf
ファイルを編集して以下の行を追加:
[archzfs] SigLevel = Never Server = http://archzfs.com/$repo/x86_64
必要であれば他のパッケージも packages.both
, packages.i686
, packages.x86_64
に追加してイメージを作成します。
# ./build.sh -v
イメージは /root/media/out
ディレクトリにできます。
プロセスの詳細は このガイド や Archiso の記事で読めます。
UEFI 環境にインストールする場合は、Unified Extensible Firmware Interface#ISO から UEFI ブータブル USB を作成する を見て UEFI に対応するインストールメディアを作成してください。
ZFS on Linux で暗号化
ZFS on Linux の安定版は直接暗号化をサポートしていませんが、zpool を dm-crypt ブロックデバイスの中に作成することができます。zpool は平文の抽象レイヤー上に作成されるので、重複排除や圧縮、データの堅牢性といった ZFS の利点を全て活かしながらデータを暗号化することが可能です。
dm-crypt (LUKS) は /dev/mapper
にデバイスを作成し、デバイスの名前は固定されます。そのため、zpool create
コマンドを変更してその名前を使う必要があります。/dev/mapper
ブロックデバイスを作成してそこから zpool をインポートするようにシステムを設定することが狙いです。zpool は複数のデバイスに作成することができるので (raid, mirroring, striping, ...)、全てのデバイスを暗号化するのが重要です。そうしないと保護が部分的に欠ける恐れがあります。
例えば、以下を使うことでプレーンな dm-crypt (LUKS は使わない) で暗号化された zpool を作成することができます:
# cryptsetup --hash=sha512 --cipher=twofish-xts-plain64 --offset=0 --key-file=/dev/sdZ --key-size=512 open --type=plain /dev/sdX enc # zpool create zroot /dev/mapper/enc
root ファイルシステムのプールの場合、mkinicpio.conf
の HOOKS 行でパスワードを入力するためのキーボードを有効にしたり、デバイスを作成、プールをロードします。以下のようになります:
HOOKS="... keyboard encrypt zfs ..."
/dev/mapper/enc
の名前は固定されているためインポートエラーは発生しません。
暗号化された zpool の作成は問題なく動作します。ただし、ディレクトリの暗号化が必要な場合、例えばユーザーのホームを保護したいとき、ZFS は機能をいくつか失います。
ZFS は平文の抽象レイヤーではなく暗号化されたデータを回覧するので、圧縮や重複排除は動作しません。暗号化されているデータは高エントロピーであり圧縮がうまく効かないのと、入力と出力が異なって重複排除ができなくなってしまうからです。不必要なオーバーヘッドを減らすために、暗号化ディレクトリにサブファイルシステムを作成して、その上で eCryptfs を使うことができます。
例えばホームを暗号化するには: (暗号化とログインの2つのパスワードは同じである必要があります)
# zfs create -o compression=off -o dedup=off -o mountpoint=/home/<username> <zpool>/<username> # useradd -m <username> # passwd <username> # ecryptfs-migrate-home -u <username> <log in user and complete the procedure with ecryptfs-unwrap-passphrase>
archzfs による chroot の応急処置
以下はメンテナンスのために archiso を使って ZFS ファイルシステムに入る方法です。
最新の archiso を起動してネットワークを立ち上げる:
# wifi-menu # ip link set eth0 up
ネットワーク接続をテスト:
# ping google.com
pacman パッケージデータベースを同期:
# pacman -Syy
(任意) テキストエディタのインストール:
# pacman -S vim
archzfs の archiso リポジトリを pacman.conf
に追加:
/etc/pacman.conf
[archzfs] Server = http://archzfs.com/$repo/x86_64
pacman パッケージデータベースを同期:
# pacman -Syy
archzfs のメンテナの PGP 鍵をローカルの (インストーライメージの) 信頼リストに追加:
# pacman-key --lsign-key 0EE7A126
ZFS パッケージグループをインストール:
# pacman -S archzfs-linux
ZFS カーネルモジュールをロード:
# modprobe zfs
プールをインポート:
# zpool import -a -R /mnt
(存在する場合) ブートパーティションをマウント:
# mount /dev/sda2 /mnt/boot # mount /dev/sda1 /mnt/boot/efi
ZFS ファイルシステムに chroot:
# arch-chroot /mnt /bin/bash
カーネルのバージョンを確認:
# pacman -Qi linux # uname -r
uname は archiso のカーネルバージョンを表示します。バージョンが異なる場合、chroot 環境の適切なカーネルバージョンで depmod を (chroot の中で) 実行してください (バージョンは pacman -Qi linux
で確認できます):
# depmod -a 3.6.9-1-ARCH
これで chroot 環境にインストールされているカーネルバージョンに合ったカーネルモジュールがロードされます。
ramdisk の再生成:
# mkinitcpio -p linux
エラーは起こらないはずです。
バインドマウント
以下では /mnt/zfspool
から /srv/nfs4/music
へのバインドマウントを作成します。バインドマウントを作成する前に zfs プールの準備ができていることを確認してください。
fstab
systemd-fstab-generator を使って systemd が fstab を mount ユニットファイルにどうやって変換するのかは systemd.mount を見てください。
/etc/fstab
/mnt/zfspool /srv/nfs4/music none bind,defaults,nofail,x-systemd.requires=zfs-mount.service 0 0
モニタリングやイベント時にメール
詳しくは ZED: The ZFS Event Daemon を見てください。
メールを送信するには msmtp などのメールフォワーダが必要です。動作することを確認してください。
設定ファイルで以下の行をアンコメント:
/etc/zfs/zed.d/zed.rc
ZED_EMAIL_ADDR="root" ZED_EMAIL_PROG="mail" ZED_NOTIFY_VERBOSE=0 ZED_EMAIL_OPTS="-s '@SUBJECT@' @ADDRESS@"
ZED_EMAIL_ADDR="root"
の 'root' は通知を受信したいメールアドレスに置き換えてください。
プールの状態に関わらずメールを受信したい場合は ZED_NOTIFY_VERBOSE=1
と設定すると良いでしょう。
設定したら zfs-zed.service
を起動・有効化してください。
verbose を 1 に設定したら、スクラブを実行することでテストできます。