zfs の便利な機能 Top10

# zfs の便利な機能 Top10

Linus が zfs を linux kernel にマージしないっていう姿勢がちょっと前に話題になっていたけど、
zfs の便利な機能を Top10 形式で出すので、zfs 広まって欲しい。
zfs をシステム管理で一度使ったことがある人にとっては、離れられないと思っている。

ただ、zfs は、もともと solaris (oracle) の機能であるので、
訴訟含めてどうなるかわからないのは、Linus の言うとおりなのかもしれない。
また、kernel にマージされていないのもあって、zfs on Linux では一部制限があったり
使いにくかったりしている。

## tl;dr;
zfs を使うなら、ストレージ関連のコマンドとして、zpool, zfs という2つのコマンドを
知っていればよく、透過圧縮などもあり、ディスクを効率的に使用できる機能も盛り沢山。
ユーザーごとの使用容量も一瞬で表示できたり、スナップショットやバックアップ関連なども容易。
さらに、ソフトウェアRAID的な機能もあるのに、別な計算機に接続して使用したりするのも簡単。



## #1 pool という概念による、容易なディスク追加
zfs はプールという概念で、ストレージを管理する。
考え方は lvm に似ているが、zfs ファイルシステムの機能の一部なので、
シームレスに使えるのが便利。

<img width="469" alt="スクリーンショット 2020-01-29 22.56.41.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/47832/2298cdae-9f62-f409-06b8-07ca72abf8b2.png">


この概念があるのでデバイスを直接意識することなく使用することができ、
プールの容量を追加するときに、プールに対してディスクを追加すればよく、メンテなども行いやすい。
pool を作る時に software raid や mirror といったことも設定することができる。
また、プールの cache として高速な ssd を設定するといったこともできる。

```sh
$ zpool create tank raidz2 c1t0d0 c2t0d0 c3t0d0 c4t0d0 c5t0d0
$ zpool status -v tank
  pool: tank
 state: ONLINE
 scrub: none requested
config:
        NAME        STATE     READ WRITE CKSUM
        tank        ONLINE       0     0     0
          raidz2-0  ONLINE       0     0     0
            c1t0d0  ONLINE       0     0     0
            c2t0d0  ONLINE       0     0     0
            c3t0d0  ONLINE       0     0     0
            c4t0d0  ONLINE       0     0     0
            c5t0d0  ONLINE       0     0     0
```

## #2 プロジェクトやユーザーごとのボリュームの管理の容易性
   tank という名前の pool を作ったら、`/tank` などに自動的にマウントされて zfs として使用することができる。
   そのまま、1つの pool を1つのファイルシステムとして使用することもできるが、
   プロジェクトごとなど管理しやすい単位で pool から切り出して使用することができる。
   pool から切り出すと、後述する snapshot やステータス情報、マウントポイントの変更、
   一括した削除などが行いやすいので、ディレクトリ作成するようなイメージで作成すると良い。
もちろん構成の異なる複数の pool を作ることもできる。

```
$ zfs create tank/project_a
$ zfs create tank/project_b
$ zfs create tank/project_c
```
   上記を行うと `/tank/project_{a-c}` というディレクトリが作られていて、そこに mount されているような形になる。
この時に、pool が共通なので全プロジェクトで共通のディスクを使用しているような形になる。
そのため、必要に応じて project ごとに使用量の上限値や、容量を確保することなどもできる。

```
$ zfs set quota=10G tank/project_a
$ zfs set reservation=5G tank/home/moore
```

`zfs list` などで zfs の情報を見ることができ、create した単位でどれぐらい使用しているのか
ということがすぐに確認できる。

```
$ zfs list
NAME                   USED  AVAIL  REFER  MOUNTPOINT
pool                   476K  16.5G    21K  /pool
pool/clone              18K  16.5G    18K  /pool/clone
pool/home              296K  16.5G    19K  /pool/home
pool/home/marks        277K  16.5G   277K  /pool/home/marks
pool/home/marks@snap      0      -   277K  -
pool/test               18K  16.5G    18K  /test
```

上記のように1段の階層だけではなく、`/`で区切って多段の階層も作ることができる。

`/tank/project_{a-c}` はデフォルトのマウントポイントで、任意の場所に変更も当然できる。


## #3 ユーザーごとの使用量把握が一瞬
  これは zfs 独特な便利な機能だと思っていて、同じファイルシステムを
  複数ユーザーで使っている場合に、誰がどれぐらいディスク消費しているのか
  ということを調べたい時があるけど、zfs ならそれが一瞬で表示できる。
  group ごとの表示も可能で、それぞれ quota などの設定もできる。

```sh
$ zfs userspace students/compsci
TYPE        NAME      USED  QUOTA
POSIX User  root      227M   none
POSIX User  student1  455M    10G

$ zfs groupspace students/labstaff
TYPE         NAME   USED  QUOTA
POSIX Group  root   217M   none
POSIX Group  staff  217M    20G
```
ここら辺は単一のボリュームサイズが大きいほど、全部のデータを見にいくdu と比べてめちゃめちゃメリット。

  同じステータス表示系ということで、ついでに iostat も紹介したい。
  pool 自体の io も見ることができるが、-v(verbose mode) でみることで、
  デバイスごとの io もここから把握できる。
  pool ごとに接続されている デバイスを確認しやすくわかりやすい。

```sh
$ zpool iostat -v
               capacity     operations    bandwidth
pool        alloc   free   read  write   read  write
----------  -----  -----  -----  -----  -----  -----
rpool       6.05G  61.9G      0      0    785    107
  mirror    6.05G  61.9G      0      0    785    107
    c1t0d0s0    -      -      0      0    578    109
    c1t1d0s0    -      -      0      0    595    109
----------  -----  -----  -----  -----  -----  -----
tank        36.5G  31.5G      4      1   295K   146K
  mirror    36.5G  31.5G    126     45  8.13M  4.01M
    c1t2d0      -      -      0      3   100K   386K
    c1t3d0      -      -      0      3   104K   386K
----------  -----  -----  -----  -----  -----  -----
```

## #4 容易にアクセス可能なスナップショット
  ストレージに snapshot 機能があるものもあるが、zfs 自体の機能を使うことで、
  利便性が高いと思っている。
  zfs で snapshot を作成する場合には、 `zfs snapshot tank/project_a@friday` のように
  zfs の名前に `@` をつけて作成するだけである。
  snapshot の作成は一瞬で終わり、その後に変更部分だけが、
  差分として残るので、コピーの様に重複してディスクを使用することもない。
  solaris では自動スナップショットなどで、毎時や毎週などの自動的なスナップショットも
  行えるが、 cron で同じようなことをすることもできる。
  名前はあるていど自由に付けられるので、要所要所で snapshot をとることもできる。
  #2 で説明した zfs create した単位で snapshot をとることができる。
  `-r` オプションを指示することで、下位の階層全てのsnapshotをとることも可能

```
$ zfs snapshot -r tank/home@now
$ zfs list -t snapshot
NAME                       USED  AVAIL  REFER  MOUNTPOINT
rpool/ROOT/zfs2BE@zfs2BE  78.3M      -  4.53G  -
tank/home@now                 0      -    26K  -
tank/home/ahrens@now          0      -   259M  -
tank/home/anne@now            0      -   156M  -
tank/home/bob@now             0      -   156M  -
tank/home/cindys@now          0      -   104M  -
```

  snapshot はアクセスの仕方も重要だと思うが、zfs の snapshot はアクセスも容易

```
$ zfs list -t snapshot
NAME                        USED  AVAIL  REFER  MOUNTPOINT
pool/home/anne@monday          0      -   780K  -
pool/home/bob@monday           0      -  1.01M  -
tank/home/ahrens@tuesday   8.50K      -   780K  -
tank/home/ahrens@wednesday 8.50K      -  1.01M  -
tank/home/ahrens@thursday      0      -  1.77M  -
tank/home/cindys@today     8.50K      -   524K  -
```

上記のような状態であれば、 `/tank/home/bob/.zfs/snapshot` のような場所にアクセスすることで、
一般ユーザーでもすぐに snapshot にアクセスすることができる。

```sh
$ ls /tank/home/ahrens/.zfs/snapshot
tuesday wednesday thursday
```

`.zfs` は通常は見えていないが、アクセスしたら自動的に mount される形となる。

また、snapshot 同士でどのファイルに差分があるのかというのも確認できたりする。

```sh
$ zfs diff tank/home/tim@snap1 tank/home/tim@snap2
M       /tank/home/tim/
+       /tank/home/tim/fileB
```

## #5 透過圧縮ファイルシステム

ここらへんも馴染みが無い人も多いかも知れないけど、透過圧縮設定ができる。
ディスクに格納する時に圧縮して保存することで、ディスクの消費量を削減する仕組み。
透過とあるように通常使用する上で、圧縮されているかどうかは意識する必要がなく、
ls などで表示した場合にも通常の使用量で見えるが、ディスクには圧縮された状態で保存される。
テキストファイルが中心など圧縮に向いているデータが多い場合には、設定を ON にすれば効果が
高くなるが、当然CPU負荷も高くなる。
ただ、昨今はマルチコアでCPUが余っている場合も多いので、そういう場合にはメリットが大きい。

```sh
$ zfs set compress=on pool/fs
```

HDDのころは無圧縮のHDDに格納されたデータを転送するより、
圧縮して小さくなったデータを転送して、CPUで展開処理が早いので、
透過圧縮ファイルシステムを使った方がファイルIOが高いということもあったりした。


## #6 重複ファイルシステム
ここら辺もあんまり馴染みない人もいるかも？？
その名の通り、重複しているデータを同じものだと認識して、ディスク消費を防ぐ機能。
重複の判定は、ストレージに格納するときのブロックサイズごとで同じかどうかを判定するので、
一部分だけを変更したような時にも有効

<img width="837" alt="スクリーンショット 2020-01-29 23.15.04.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/47832/66a1c558-8292-0a73-1061-d465b8579f65.png">


全く同じデータをコピーして使うような環境だとかなり効くやつ。

ただ、上記を読んですぐにわかる人もいるかもだけど、同じかどうか判定するために、ファイルシステムの
サイズに比例してメモリをかなり消費する。

```
zfs set dedup=on rz2pool/data1
```

## #7 他の筐体へ移す際の容易性

pool という概念があるので、ディスクがどのように使われているか分からず、
もし本体が壊れた時とか、OSを入れ替えたい時に心配だという人もいるかもしれないけど、

OSが生きているなら `export` コマンドの取り外すコマンドを実行して、
新たな環境に全てのディスクつないで、 `import` を実行すると `/dev/dsk/` 配下を
全部確認して、import できるディスクを探索してくれる。 


```
$ zpool export tank
```

```
$ zpool import
 pool: tank
    id: 11809215114195894163
 state: ONLINE
action: The pool can be imported using its name or numeric identifier.
config:

        tank        ONLINE
          mirror-0  ONLINE
            c1t0d0  ONLINE
            c1t1d0  ONLINE
$ zpool import tank
```

また、ついでに紹介しておくと、ディスクまわりでは nfs 設定を設定するために、`/etc/exports` などを
設定することが多いが、zfs だとこの設定もファイルシステム上で設定すれば良い。

```
$ zfs set share=name=fs1,path=/rpool/fs1,prot=nfs rpool/fs1
```

この設定は、export, import してOS環境が変わっても、そのまま引き継がれるので、移行も容易。

```
$ zfs set sharenfs=on rpool/fs1
```



## #8 バックアップの容易性
データを扱う上で、どうしても無くなったら困るファイルは、RAIDだけではなく
他のディスクなどにコピーすることもあると思う。
こういう時に使えるのが、`send`, `recv` 
ディスクのボリュームが大きければ大きいほど、`rsync` とかでもコピーするのはなかなか辛い。

zfs では #4 で説明したスナップショット機能と連携して、
`snapshot` した時のデータをそのままストリームデータとして `send` できる。
二つの `snapshot` があれば、その差分だけを送付することも可能。

以下のコマンド例はそのまま別ホストで受けて、`recv` しているけど、
tgz とかの単一ファイルで残しておくこともできる。

```
$ zfs send -i tank/dana@snap1 tank/dana@snap2 | ssh host2 zfs recv newtank/dana
```

## #9 統一されたコマンド群
  ここまでのコマンド例を見て分かるように、
  `zpool`, `zfs` という 2つのコマンドしか使用していない。
  その2つを主コマンドとして機能ごとにサブコマンドで分ける形になっている。
  `git` や `docker` などのコマンドと似たような構成になっている。
  `pvs`, `vgs`, `lvm`, `lvs`, `mkfs` などなどどのコマンド使うんだっけと悩むことが少ない。
  `zpool iostat` や zfs に関するコマンドの履歴を表示する`zpool history` など
  ストレージに関することは全てこの2つのコマンドに任せる形で運用することができる。

```sh
$ zpool history
History for 'newpool:'
2007-04-25.11:37:31 zpool create newpool mirror c0t8d0 c0t10d0
2007-04-25.11:37:46 zpool replace newpool c0t10d0 c0t9d0
2007-04-25.11:38:04 zpool attach newpool c0t9d0 c0t11d0
2007-04-25.11:38:09 zfs create newpool/user1
2007-04-25.11:38:15 zfs destroy newpool/user1
```

  厳密には、zdb という関連コマンドもあるが、必須コマンドではない。

## #10 信頼性
データを扱う上で、信頼性が一番最後に来るのも微妙な気もするが、
ここはあって当たり前の必然な機能。
特に zfs では独自の通常のRAID5などよりも信頼性を高めた RAID-Z の
ような機能もあって、特に信頼性には力を入れている気がする。
zfs はこんなに高機能なのに、初版から 10年以上経過しているし、
最近は ubuntu がサポートを強化したりしていたりもするので、ほんと流行って欲しい。


----
もともと solaris の機能ということで、oracle や 富士通から
情報が提供されているので、正式な情報はそちらで確認してもらいたい。


引用元
https://docs.oracle.com/cd/E24845_01/html/819-6260/zfsover-1.html
https://www.fujitsu.com/jp/documents/products/computing/servers/unix/sparc/technical/document/solaris11_zfs_gde01.pdf
https://www.fujitsu.com/jp/documents/products/computing/servers/unix/sparc-enterprise/technical/documents/00_ZFS.pdf
https://www.fujitsu.com/jp/documents/products/computing/servers/unix/sparc-enterprise/technical/documents/zfs_apply.pdf