ZFS

提供: ArchWiki
移動先: 案内検索

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 カーネルモジュールを開発することを目標としています。

ノート: ZFS コードの CDDL ライセンスと Linux カーネルの GPL に法的な互換性がないため ([2],CDDL-GPL,ZFS in Linux)、ZFS の開発はカーネルによってサポートされていません:
  • ZFS は Arch User Repository に含まれており非公式の archzfs リポジトリから使うこともできます。
  • ZFSonLinux プロジェクトは最新の Linux カーネルに追従しています。ZFSonLinux の安定版がリリースされた後に Arch の ZFS メンテナも同バージョンをリリースします。
  • 新しいバージョンのカーネルがリリースされてから ZFSonLinux によってサポートされるまでタイムラグがあるため、場合によっては通常のローリングアップデートができなくなる可能性があります。

インストール

警告: dkms バージョンのパッケージを使用しない場合、ZFS と SPL のカーネルモジュールは特定のカーネルバージョンに拘束されます。AUR や archzfs リポジトリに新しいパッケージがアップロードされるまで、カーネルアップデートを適用することはできません。
ヒント: 使用しているカーネルが新しすぎる場合、archzfs リポジトリから古いバージョンのカーネルにダウングレードすることができます。

Arch User Repository または archzfs リポジトリから以下のパッケージのどれかをインストールしてください:

  • zfs-linuxAUR - 安定版のリリース [3]
  • zfs-linux-gitAUR - 開発版のリリース (新しいバージョンのカーネルをサポート) [4]
  • zfs-linux-ltsAUR - LTS カーネル用の安定版リリース。
  • zfs-dkmsAUR - ダイナミックカーネルモジュールをサポートしているバージョン。

上記のパッケージにはそれぞれ zfs-utils, spl-linux, spl-utils-linux が存在します。SPL (Solaris Porting Layer) は ZFS を使用するために Solaris の API を実装する Linux カーネルモジュールです。

パッケージをインストールしたらコマンドラインで zpool status を実行してテストしてください。"insmod" エラーが表示される場合、depmod -a を試してみてください。

Archiso

ZFS の root ファイルシステムに Arch Linux をインストールする場合は、Arch User Repositoryarchzfs リポジトリから zfs-linux-gitAUR をインストールしてください。

詳しい情報は ZFS に Arch Linux をインストールを参照。

DKMS

DKMS (Dynamic Kernel Module Support) を利用することでカーネルのアップグレードがあったときに自動的に ZFS モジュールを再ビルドすることができます。

zfs-dkmsAURzfs-dkms-gitAUR をインストールして、パッケージから表示されるインストール後の手順に従ってください。

ヒント: pacman.confIgnorePkg エントリにパッケージを追加することでパッケージがアップグレードされるのを止めることができます。

ZFS の実験

~/zfs0.img ~/zfs1.img ~/zfs2.img などのシンプルなファイルの仮想ブロックデバイス (ZFS では VDEV と呼称) を使って、データを消失する危険性なく、ZFS の実験を行いたいユーザーは ZFS/仮想ディスクの記事を見て下さい。RAIDZ アレイの作成や、意図的にデータを破損させてそれを復元したり、データセットのスナップショットなどの一般的な作業を取り扱っています。

設定

ZFS はその開発者から"ゼロアドミニストレーション"のファイルシステムであるとされています。そのため、ZFS の設定はとても簡単です。設定は主に2つのコマンドを使って行います: zfszpool

ノート: 下のセクションは root ファイルシステムを ZFS ボリュームにインストールしたい場合にのみ必要になります。データパーティションを ZFS で扱うユーザーは次のセクションを読む必要はありません。

自動起動

ZFS を"ゼロアドミニストレーション"の名に負うように使うには、zfs デーモンを起動時にロードする必要があります。このため /etc/fstab で zpool をマウントする必要はありません。zfs デーモンが自動的に zfs プールをインポートしてマウントを行います。デーモンは /etc/zfs/zpool.cache ファイルを読み込んで zfs プールをマウントします。

zfs デーモンによって自動でマウントしたいプール毎に次を実行:

# zpool set cachefile=/etc/zfs/zpool.cache <pool>

ブート時に自動的に起動するようにサービスを有効化:

# systemctl enable zfs.target

デーモンを手動で起動するには:

# systemctl start zfs.target
ノート: ZOL バージョン 0.6.5.8 から ZFS のサービスユニットには変更が加えられ、明示的に ZFS サービスを有効化しなくてはならなくなりました。詳しくは https://github.com/archzfs/archzfs/issues/72 を参照。

ZFS プールを自動的にマウントするには以下のサービスを有効にしてください:

# systemctl enable zfs-import-cache
# systemctl enable zfs-mount

ストレージプールの作成

利用できるドライブの一覧を見るには # parted --list を使います。zfs ファイルシステムを作成する前にドライブをパーティションする必要はありません、推奨もされていません。

ノート: デバイスの一部または全部でソフトウェア RAID を使っている場合は、昔の RAID 設定情報を全て削除してください (Mdadm#デバイスの準備)。
警告: セクターサイズが 4KB の Advanced Format ディスクでは、パフォーマンスを最大限引き出すために ashift を 12 にすることが推奨されています。Advanced Format ディスクはレガシーなシステムとの互換性のために512バイトのセクターサイズをエミュレートするため、ZFS が使用する ashift の数字が望ましい数値にならないことがあります。プールを一度作成してしまった場合、ashift オプションを変更するにはプールを再作成するしかありません。また、ashift を 12 にすると利用できる容量が減少します。1.10 What’s going on with performance?, 1.15 How does ZFS on Linux handles Advanced Format disks?, ZFS and Advanced Format disks を見て下さい。

ドライブの一覧を確認できたら、次は 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
警告: デバイス名 (例: /dev/sda, /dev/sdb) を使用して zpool を作成した場合、起動時に ZFS が zpool を認識できなくなる可能性があります。

そして、いよいよ ZFS プールを作成します:

# zpool create -f -m <mount> <pool> raidz <ids>
  • create: プールを作成するサブコマンド。
  • -m: プールのマウントポイント。指定されない場合、プールは /<pool> にマウントされます。
  • pool: プールの名前。
  • raidz: デバイスのプールから作成される仮想デバイスのタイプ。Raidz は raid5 の特殊な実装です。raiz に関する詳細は Jeff Bonwick's Blog -- RAID-Z を見て下さい。
  • 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.beta3 現在、GRUB は ZFS-on-Linux 0.6.5.7 の全ての機能をサポートしていますが、ZoL の Git ブランチには GRUB によってまだサポートされていない機能 (large_dnodes) が追加されています。

# zpool create -f -d \
               -o feature@async_destroy=enabled \
               -o feature@empty_bpobj=enabled \
               -o feature@lz4_compress=enabled \
               -o feature@spacemap_histogram=enabled \
               -o feature@enabled_txg=enabled \
               -o feature@hole_birth=enabled \
               -o feature@bookmarks=enabled \
               -o feature@filesystem_limits=enabled \
               -o feature@embedded_data=enabled \
               -o feature@large_blocks=enabled \
               <pool_name> <vdevs>

チューニング

一般

zfs ファイルシステムでは多数のパラメータを使うことができます。パラメータの完全なリストは zfs get all <pool> で見ることが可能です。調整するパラメータとしては atimecompression が一般的です。

atime はデフォルトで有効にされていますが、ほとんどのユーザーにとっては zpool に余分な書き込みになります。zfs コマンドを使うことで atime を無効にできます:

# zfs set atime=off <pool>

atime を完全にオフにする代わりとして、relatime を使うこともできます。ext4/xfs のデフォルトの atime の処理と同じで、変更日時が更新されたとき、または24時間で一度もアクセス日時が更新されなかった場合にのみ、ファイルのアクセス日時が更新されます。atime=off と atime=on の折衷案になります。このプロパティは atimeon になっているときだけ適用されます:

# 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
ノート: これらのパラメータのチューニングは RDBMS などの特別なアプリケーションで相応しい類のものです。/home ディレクトリなどの一般目的のファイルシステムで上記チューニングを設定すると ZFS のパフォーマンスに害を与える可能性があります。

/tmp

ZFS を使って /tmp ディレクトリを保存したい場合、ファイルシステムの同期を無効にすることで /tmp への書き込みを行うアプリケーションのパフォーマンスを向上させることがあります。これによって ZFS はアプリケーションの同期リクエスト (例: fsyncO_SYNC) を無視して、すぐに戻るようになります。アプリケーションサイドのデータの一貫性を保つのが難しくなる一方 (データベースで同期を無効化してはいけません)、/tmp のファイルはあまり重要でないことが多いため、影響は限られます。ZFS 自体の整合性には影響を与えないので注意してください。アプリケーションがディスク上にあると期待しているデータが実際に書きだされなくてクラッシュが起こる可能性があるくらいです。

# zfs set sync=disabled <pool>/tmp

さらに、セキュリティ上の理由で、/tmp ファイルシステムの setuiddevices を無効化すると良いでしょう。特権昇格攻撃やデバイスノードの使用をふせぐことができます:

# 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 プールをスクラブするべきです。プールをスクラブするには:

# 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 bigdata

Zpool の名前を変更

既に作成済みの zpool の名前の変更は2ステップで行います:

# zpool export oldname
# zpool import oldname newname

別のマウントポイントを設定

指定の zpool のマウントポイントは一つのコマンドで随意に移動することができます:

# zfs set mountpoint=/foo/bar poolname

スワップボリューム

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 自動スナップショットサービス

AURzfs-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-auto-snapshot-git はスクラブ中にはスナップショットを作成しません (ZFS#スクラブを参照)。元の systemd ユニットを編集して ExecStart 行から --skip-scrub を削除することでスクラブ中でもスナップショットを作成するように設定できます。Systemd#ユニットファイルの編集を見てください。

ZFS スナップショットマネージャ

AURzfs-snap-managerAUR パッケージは ZFS データセットのスナップショットを毎日作成して "Grandfather-father-son" 方式で削除していく python サービスを提供します。7日毎、5週間毎、3ヶ月毎、2年間毎などのスナップショットを保持するよう設定できます。

このパッケージは ZFS が動作している他のマシンへのレプリケーションもサポートしており zfs sendzfs 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

起動時に 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

Tips and tricks

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

systemd マウントユニット

zfs プールの準備をする前に fstab が読み込まれるため、fstab を使って zfs 上のディレクトリを他のディレクトリにバインドマウントできない場合、systemd の mount ユニットを使うことでバインドマウントすることが可能です。マウントユニットの名前は "Where" の後ろに記述するディレクトリと一致している必要があります。スラッシュはマイナスに置き換えてください。詳しくは [5][6] を参照。

srv-nfs4-music.mount
[Mount]
What=/mnt/zfspool
Where=/srv/nfs4/music
Type=none
Options=bind

[Unit]
DefaultDependencies=no
Conflicts=umount.target
Before=local-fs.target umount.target
After=zfs-mount.service
Requires=zfs-mount.service
ConditionPathIsDirectory=/mnt/zfspool

[Install]
WantedBy=local-fs.target

参照

Aaron Toponce は ZFS に関する17部からなるブログ記事を執筆しています。素晴らしい読み物です。
  1. VDEVs
  2. RAIDZ Levels
  3. The ZFS Intent Log
  4. The ARC
  5. Import/export zpools
  6. Scrub and Resilver
  7. Zpool Properties
  8. Zpool Best Practices
  9. Copy on Write
  10. Creating Filesystems
  11. Compression and Deduplication
  12. Snapshots and Clones
  13. Send/receive Filesystems
  14. ZVOLs
  15. iSCSI, NFS, and Samba
  16. Get/Set Properties
  17. ZFS Best Practices