ZFSがあればGitなんか要らない?

ZFSを少し触ってみました。ZFSはOracle(その前はSun)の次世代ファイルシステムです。元はSolaris向けに開発されたものですが、オープンソースなのでLinux(0.6.1以降が製品版として安定しているようですMacにも移植されています。ファイルシステムといっても、ZFSはボリュームマネージャでもあるので、ディスクのパーティション管理もやってくれます。ZFSがなぜそんなにクールかといえば、データ破損対策、RAIDのサポート、スナップショットやコピーオンライトの実装、そしてバックアップ時のフレキシブルで効率の良いデータ転送などが装備されているからです。ZFSを使って、バージョン管理システムのGit(Gitじゃないバージョン管理システムでも構わないのですが)のいろいろな機能をどこまで実行できるのか、お見せしようと思います。もちろん、本気で”ちゃんとした”バージョン管理システムを捨てたほうがいいと言うつもりはありませんよ。でもファイルシステムのレベルでここまでできると理解するのにはいい例だと思います。

ZFSをインストールするのは簡単です。MacだったらOpenZFS on OS Xのサイトに行ってパッケージをインストールすればいいのです。Ubuntuでは次のようにします。

$ sudo apt-add-repository ppa:zfs-native/stable
$ sudo apt-get update
$ sudo apt-get install ubuntu-zfs

プールとファイルシステム

さて準備ができたので新たにZFSストレージプールとファイルシステムを構築してみましょう。ドライブがあればそれを利用すればいいですし、ない場合はディスクのかわりにファイルを作成すれば、試してみるには十分です。例えば10Gのファイルを作成するにはこのようにddコマンドを使います。

$ dd if=/dev/zero of=/tmp/disk1.img bs=1024 count=10485760

RAIDの設定を試してみるには、disk1.imgとは違う名前でもう1つファイルを作りましょう。次にzpool createを使ってストレージプールを作成します。ディスクがあるならディスクラベル(例えば/dev/sda、/dev/sdbなど)、またはID(/dev/disk/by-id/…)も利用できます。今回はファイルヘのフルパスを利用します。

様々なタイプのプールを作ることができますが、ミラー化するには以下のようにします。

$ sudo zpool create mypool mirror /tmp/disk1.img /tmp/disk2.img

ここでは”mypool”という名前のプールが、2つの”デバイス”をミラーして、/mypool (Linuxの場合。Macでは/Volumes/mypool)直下にマウントしています。使用可能な容量を確認するにはzfs listを使います。

$ sudo zfs list
NAME         USED   AVAIL   REFER  MOUNTPOINT
mypool      433Ki  9,78Gi   370Ki  /Volumes/mypool

もう1つの方法としては、すべてのデバイスから使用可能な領域を集めて、それを1つの大きなドライブとして扱う方法もあります。mypoolを既に作成してしまっていたら破棄してください。

$ sudo zpool destroy mypool

それからミラーされていないプールを作成します。

$ sudo zpool create mypool /tmp/disk1.img /tmp/disk2.img
$ sudo zfs list
NAME         USED   AVAIL   REFER  MOUNTPOINT
mypool      439Ki  19,6Gi   370Ki  /Volumes/mypool

約20Gの容量が利用可能になっています。

ストレージプールについては途中でディスクを追加したり交換したりなど、いろいろとできることがありますが、今のところはシンプルな設定にしておきましょう。

ここまで/Volumes/mypoolまたは/mypool直下にファイルをマウントしてきましたが、このようなZFSの使い方はあまりお勧めしません。そのかわりに、プール内にいくつかの異なるファイルシステムを作成してみましょう。それぞれのファイルシステムに対して、暗号化・圧縮・割り当てなどの様々なプロパティを設定することができます。また、ファイルシステムごとに個別のスナップショットを取ることもできます。他にも、SambaやNFSを介してファイルシステムを共有したり、別のサーバ上のプールにファイルシステムのスナップショットを送ったりできます。

このように、ファイルシステムはかなりスゴいのです。

ZFSファイルシステムではzfsコマンドを使います(プールの際にzpoolコマンドを使うのと同じです)。

$ sudo zfs create mypool/test

これでファイルシステムが新規作成され、/mypool/test(Macの場合は/Volumes/mypool/testとなります)下にマウントされます。ちなみに、ファイルシステム(およびプール)は、-mオプションでどこにでもマウントできます。面白いのですが、実は作成後でもマウントポイントを変更することができるんです。

$ sudo zfs set mountpoint=/test mypool/test

こうすれば、ファイルシステムを/test下に再マウントできます。ファイルシステムのプロパティを確認するには、zfs get allコマンドを使います。

$ sudo zfs get all mypool/test
NAME         PROPERTY              VALUE                 SOURCE
mypool/test  type                  filesystem            -
mypool/test  creation              di aug 20 14:47 2013  -
mypool/test  used                  442Ki                 -
mypool/test  available             9,78Gi                -
mypool/test  referenced            442Ki                 -
mypool/test  compressratio         1.00x                 -
mypool/test  mounted               yes                   -
mypool/test  quota                 none                  default
mypool/test  reservation           none                  default
mypool/test  recordsize            128Ki                 default
mypool/test  mountpoint            /test                 local
mypool/test  checksum              on                    default
mypool/test  compression           off                   default
mypool/test  atime                 on                    default
mypool/test  devices               on                    default
mypool/test  exec                  on                    default
mypool/test  setuid                on                    default
mypool/test  readonly              off                   default
mypool/test  snapdir               hidden                default
mypool/test  canmount              on                    default
mypool/test  copies                1                     default
mypool/test  version               5                     -
mypool/test  utf8only              on                    -
mypool/test  normalization         formD                 -
mypool/test  casesensitivity       sensitive             -
mypool/test  refquota              none                  default
mypool/test  refreservation        none                  default
mypool/test  primarycache          all                   default
mypool/test  secondarycache        all                   default
mypool/test  usedbysnapshots       0                     -
mypool/test  usedbydataset         442Ki                 -
mypool/test  usedbychildren        0                     -
mypool/test  usedbyrefreservation  0                     -
mypool/test  logbias               latency               default
mypool/test  sync                  standard              default

上記のプロパティの中には、便利な機能がたくさんあります。例えば、圧縮をする場合はこうなります。

$ sudo zfs set compression=on mypool/test

これで、コマンド実行後にファイルシステムに書き込まれたものはすべて圧縮されます。

Gitなんか要らない?

GitのかわりにZFSを採用するのは、名案とは言えないかもしれません。ただし、ZFSがファイルシステムのレベルでできることを理解していただくために、Git特有の操作を例にしていくつかご紹介しましょう。
* リポジトリの作成
* バージョンのコミットとタグ付け
* ブランチの作成
* 別ストレージプール(別筐体を含む)からのプッシュとプル

お気づきかと思いますが、上のリストにはマージ機能がありませんね。私の知る限りでは、ZFSはサポートを行っていません。

リポジトリの作成

まずファイルシステムを作成しましょう。今回の解説用に、階層構造を作ります。このファイルシステムを”zfsgit”と名付けます。もちろん、ファイルシステムの階層は、いくらでも深くすることができます。次に、ファイルシステムのルートをカレントユーザにchownします。そうすれば、ファイル作成・更新・削除のためにsudoする必要はありません。

$ sudo zfs create mypool/projects
$ sudo zfs create mypool/projects/zfsgit
$ sudo chown $(whoami) /Volumes/mypool/projects/zfsgit
$ cd /Volumes/mypool/projects/zfsgit

これでリポジトリと同様のものが準備できました。リポジトリに関しては解決です。
では、ファイルを作成して何か書き込んでみましょう。

$ echo "Hello" > file.txt

バージョンのコミットとタグ付け

コミットとタグ付け、つまり、復旧できるように過去のバージョンを保持しておくには、ZFSの”スナップショット”を使います。ZFSスナップショットには、明示的に名前をつけなければなりません。最初のスナップショットを”firstcommit”と名付けましょう。ファイルシステム名の後に@とスナップショット名を付加します。

$ sudo zfs snapshot mypool/projects/zfsgit@firstcommit

では、下記のようにファイルを少しだけ変更してみましょう。

$ echo "world" >> file.txt'''

結果を確認します。

$ sudo zfs diff mypool/projects/zfsgit@firstcommit
M   /Volumes/mypool/projects/zfsgit/file.txt

残念ながらテキストレベルの差分は確認できないのですが、少なくともどのファイルが変更されたかは分かります。では、再度コミットを実行してみましょう。

$ sudo zfs snapshot mypool/projects/zfsgit@secondcommit

現在のスナップショットを一覧表示するには、次のコマンドを実行します。

$ sudo zfs list -t snapshot
NAME                                   USED   AVAIL   REFER  MOUNTPOINT
mypool/projects/zfsgit@firstcommit    146Ki       -   370Ki  -
mypool/projects/zfsgit@secondcommit       0       -   386Ki  -

ここで、さらにファイルに変更を加えます。

$ echo "ladies..." >> file.txt

うーん、イマイチですね。では、1つ前のスナップショットにロールバックしてみましょう。

$ sudo zfs rollback mypool/projects/zfsgit@secondcommit
$ cat file.txt
Hello
world

無事、1つ前のバージョンに戻りました。

ブランチの作成

機能的に見てGitのブランチ作成と同じことが、zfs cloneで実現できます。次のコマンドを実行すれば、特定のスナップショットを元にしたファイルシステムのクローンを作成できるのです。

$ sudo zfs clone mypool/projects/zfsgit@firstcommit mypool/projects/zfsgit_branch

これで、コピーオンライト形式の新しいファイルシステムがmypool/projects/zfsgit_branch以下にマウントされました。この処理はデータのコピーを伴わないため非常に軽く、初回に追加のディスク領域を消費することはまずありません。

リポジトリのプッシュとプル

ZFSでは、異なるストレージプールにファイルシステムを転送することができます。転送先はローカル、リモートを問わず、差分転送も可能です。では、実際にやってみましょう。まず”mypool2″という名前の新しいストレージプールをローカル環境に作成してください。これで、任意のスナップショットを別のストレージプールに”プッシュ”する準備が整いました。実際のコマンドは下記の通りです(rootユーザで実行してください)。

$ zfs send mypool/projects/zfsgit@firstcommit | zfs receive mypool2/zfsgit

下のように、SSHを介した処理と同じ動きをすると考えれば理解しやすいでしょう。

$ zfs send mypool/projects/zfsgit@firstcommit | ssh root@myserver zfs receive mypool/zfsgit

上記のようにすれば、スナップショット作成時のファイルシステム全体がプッシュされます。また、過去に1つ前のスナップショットをプッシュしていた場合は、-iオプションを付加することで前回と今回の差分だけをプッシュすることもできます。

$ zfs send -i mypool/projects/zfsgit@firstcommit mypool/projects/zfsgit@secondcommit | zfs receive mypool2/zfsgit

この差分オプションは、大規模なファイルシステムのバックアップを定期的に行う場合に有効です。もちろん上記のコマンドはUNIXのパイプを使用しているに過ぎませんから、zfs sendの出力結果をファイルに書き込んで、Amazon S3などにアップロードするといった処理も行えます。

$ zfs send mypool/projects/zfsgit@firstcommit > backup.dump

一方、ファイルシステムをプッシュではなく”プル”するには、次のようにSSHを介してZFSのreceiveコマンドを使います。

ssh root@myserver zfs send mypool/zfsgit@secondcommit | zfs receive mypool/zfsgit

ZFSを採用すべきか

ZFSは、少なくともSolarisやLinux上ではかなり使い勝手が良く、安定しています。Mac上でも安定稼働するどうかは、今の時点ではまだ確信が持てません。Linuxのルートファイルシステムとして採用するには、現時点ではまだ少し問題があるように思います。しかし、それもすぐに解決されることでしょう。私はまだ信頼性とパフォーマンスを語れるほどZFSを十分に使い込んでいませんが、ネット上での評判は良いようです。

ただし、ZFSが唯一の選択肢というわけではありません。例えばLinuxのBtrfsにも同じような機能が多く備わっています。ただBtrfsは比較的新しいシステムでまだ成熟していないため、ZFSほど安定していません。どちらにせよ、こうしたファイルシステムには楽しめる機能がたくさん実装されています。ZFSについてもっと詳しく知りたい方は、Oracle Solaris ZFS 管理ガイドをぜひチェックしてみてください。大変読みやすく、LinuxとMacの両方に対応しています。


Git Logo by Jason Long is licensed under the Creative Commons Attribution 3.0 Unported License