Chienomi

Btrfsを13年使ったのでその経験の話

Live With Linux::practical

私がBtrfsに始めて触れたのは、日経Linuxの2009年の記事であった。

その後新しい(有望な)ファイルシステムとしてBtrfsを扱ってきたが、本格的に、という意味では8台のディスクからなるBtrfsボリュームを形成した2014年からと言えるだろう。そこからカウントすれば8年だ。

Btrfsに対しては先入観や空疎な風説に惑わされ知ったように劣ったファイルシステムであると語る人が多くいる。 しかし、そのような人はBtrfsをちゃんと運用した経験を持たないだろう。

一方、しっかりとしたBtrfs運用に関する話をネットで見つけるのも難しい。 そこでちょうどいいタイミングなのでBtrfsを運用してどうだったかということを述べていこうと思う。

なお、私はBtrfsを実用する前は、XFS on LVMを利用していた。

Btrfsの概要

BtrfsはLinuxのファイルシステムである。 特に堅牢性に優れている。

BtrfsはZFSの劣化クローンであるという人もいるが、これは事実ではない。 BtrfsがZFSの影響を受けているのは恐らく事実である。ZFSのような機能を求めてもいた。 だが、別にそれは「ZFSがLinuxで使えないから」ではない。Btrfsを作りたかったから作った、という話である。

実際、機能的にもZFSとは結構違う。

当初、フラッシュメモリ向けのファイルシステムであるというように言われることもあったが、特にフラッシュメモリ特化というわけではなく、汎用性が高い。

Btrfs運用上の話

ボリューム構成

この話は非常に重要だ。

Btrfsは複数の異なるサイズのディスクからなるボリュームを作ることができる。 これは「JBODではないか、珍しくもない」と思うかもしれないが、Btrfsの場合はそうではない。 実際のディスク容量に併せてファイルを分散配置したり、可能な範囲でストライピングしたりできるのである。

これは他では類を見ない強力な柔軟性だ。

BtrfsはRIAD0/1/5/6/10をサポートする。 メタデータとデータそれぞれに対して設定可能だ。

BtrfsのRAID5/6が使えないと思っている人がいるようだが、それはだいぶ昔の話だ。2017年に修正されている。 パリティの再計算は非常に時間がかかるものだが、Btrfsの場合RAID1のリバランスも非常に時間がかかるため大した問題ではない。

構成に必要な台数を満たしていれば、あとからディスクを追加したり、(m/dともに冗長性のあるRAIDレベルの場合に)ディスクを交換したりすることもできる。この場合にリバランスが発生するが、リバランスは極めて時間がかかる上に、ディスクの負担もかなり大きい。 正直なところ、バックアップを用意してボリュームを作り直し、複製するという方法をとったほうが確実で安全だ。1台ディスクが壊れたために交換してリバランスしたら、別のディスクが壊れて復旧不能になった、という経験もある。同じタイミングで導入したディスクであれば同じタイミングで壊れてもおかしくないため、そのタイミングで大きな負担をかけないほうが良いだろう。 少なくとも、ディスクの交換・リバランスを行う前に、roでマウントしバックアップしたほうが良い。

複数のブロックデバイスからなるファイルシステムを作りたい場合、Btrfsは明確なアドバンテージを持っている。 ZFSよりも柔軟であり、GFS2やOCFS2などと比べ扱いやすい。

Btrfsは利用できるか、信頼できるか

Btrfsは普通のファイルシステムとして利用できる。

つまり、耐障害性がほしければRAIDを組むべきだし、失いたくないデータであるならばバックアップを取るべきである。 Btrfsの堅牢性は突然の電源断や書き込み中のディスク障害などに対して発揮される。また、ファイルシステムそのものがRAID機能を持ち、dm-raidのようなレイヤーを噛ませる必要がないのも魅力的だ。

BtrfsのRAID機能はdm-raidほどしっかりしたものではないが、LVMよりも強力だ。

Btrfs固有の機能を一切使わないにも関わらずBtrfsを使うのはメリットに乏しいかもしれない。 しかし、「Btrfsの機能を使わないならばBtrfsを選択すべきでない」といったことは一切ない。 Btrfsは十分な性能を持っており、耐障害性も高いのだ。

Btrfsは障害が多いか

No.

Btrfsを運用していて「readonlyになる」という問題には何度か遭遇しているが、基本的にファイルシステムに関係ないディスク等の問題である。readonlyに落ちやすい傾向にはあるが、それはBtrfsの堅牢性故に怪しいディスクをさっさとroにするという意味で悪くない。 また、ATAエラーが発生するようなディスクでroマウントできる場合が多いように感じられる。

私が運用した限り、Btrfsが他のファイルシステムと比べて障害が多いという事実はない。

また、もし障害が起きた場合にデータが救い出せる可能性は他のファイルシステムよりも有意に高い。

Btrfsは遅いか

場合による。

これは「状況による」ではなく「タイミングによる」である。

そもそもBtrfsは高速性ではなく堅牢性を目指したファイルシステムである。 そのため、速くないのはある程度「仕方ない」とも見れる。

だが、Linux 5.17現在、Ext4と比べ特にBtrfsが遅かったりはしない。SSD上の動作であればむしろ有利なくらいだ。 つまり、Ext4のほうが速く、Btrfsが遅いカーネルもある。

例を示そう。 Linux5.8ではPhoronixのテストの結果ではXFSが非常に速く、Ext4が遅い。

しかし、Linux5.14ではPhoronixのテストでExt4, XFS, Btrfsは同じようなものである。

このように活発に開発されているファイルシステム実装は、カーネルバージョンごとに大きく変わる。 その結果速くなるので、どのファイルシステムが速い遅いとは言い難い。 XFSもExt4もBtrfsも、登場当初からは考えられないほど速くなっている。

少なくとも、Btrfsが極端に遅いという事実はない。

ただし、Btrfsは少し重いというのはある。ただし、(AES-NIを使っているとしても)LUKSのほうが重く、それ以上にSSHが重いため、現実的にBtrfsの重さが問題になるようなケースは非常に限られている。

Btrfsの何が良いのか

まず、「柔軟に複数のディスクからなるボリュームを作れる」「他のファイルシステムより堅牢である」は前提としよう。

その上で、Btrfsはサブボリュームの便利さを挙げたい。

Btrfsのサブボリュームは基本的にディレクトリである。まず大きな違いはsubvol=の形でサブボリュームだけをマウントできるということだ。マウントオプションを変更することもできないので、あまり便利なものではなさそうに見える。バインドマウントで十分だと思うかもしれない。

だが、サブボリュームの存在によりスナップショットが使える。スナップショットもサブボリュームの一種だが、ある状態のファイル群を記録する。これはハードリンクのようなものだが、もっと柔軟だ。

もしスナップショット上のあるファイルが他のサブボリューム上のファイルと同じ内容同じ実体のままであれば、実体はひとつとなる。しかし、もとのサブボリュームのファイルが書き換えられた場合、その瞬間に別のファイルになる。 ハードリンクを用いた差分バックアップをものすごく便利にしたような形になっている。

そしてこのスナップショットはbtrfs sendによってバックアップを保存したり、バックアップを転送することができる。 バックアップしたい、あるいは必要に応じて巻き戻したい単位にサブボリュームを切ることで取り回しがとても良くなる。

また、スナップショットを使うことで間違ってファイルを消してしまうようなヒューマンエラーに対してリカバーが効くようになる。 こまめにスナップショットを取り、不要であると確信がもてたときに古いものから消していけばよい。

サブボリュームによって扱いが厄介であるということもなく、外側のボリュームから見るとサブボリュームはただのディレクトリに見え、そのディレクトリに対して書き込みを行っても問題ない。

space_cacheについて

space_cacheは今ならv2を使うという選択肢があるが、基本的にnospace_cacheで運用するのが良いと思う。 特にHDDでは、キャッシュのためにあっちゃこっちゃしてしまうケースを避けたほうがメリットが大きい。

サイズが大きく、なおかつ非常に高速なストレージであればspace_cache=v2が良いかもしれない。

圧縮について

lzo圧縮の速度は、私手持ちの5950Xでのも2000MB/s程度なので、PCIe SSDで圧縮を行うべきではない。

単独のSATA SSDの場合、lzo圧縮のほうが速いと期待できる。 HDD RAID0/5/6の場合、速いかどうかは処理能力にもよる。

Btrfsを使うのを避けるべきケースはあるか

容量の小さいリムーバブルディスクに使うのはやめたほうが良い。

Btrfsはあまり空間効率がよくないし、メモリも多く必要とする。 これをデメリットと感じるのであれば避けたほうが良い。

Btrfsで明確に問題として挙げられるのは、Btrfs上にスワップファイルを配置できないということだ。 Btrfs上にイメージファイルを作り、ループバックデバイスにすることでスワップファイルを扱うことができるが、Btrfs上のファイルに対してハイバネートするのは支障がある。

最近は私はシステムバックアップをとらないで、複数台運用でシステム障害発生時はシステムを作り直すような形に変えているので、ルートファイルシステムをBtrfsで切ることはしなくなっている。「インストーラーの自動設定で設定できない」もひとつのデメリットだ。ただし、稀に「Btrfsにしておけばよかったな」と思うようなこともなくはない。特定のディレクトリに対してバックアップをとったりスナップショットを取りたいと思うことがなくはないためだ。 だが、特にExt4で困ったとまでなったことはない。インストーラーがExt4に自動設定するならそのままでもいいかなと思う。

ちなみに、Manjaro Linuxの場合以前はBtrfsを使おうとすると手動で介入させる必要があったけれど、今は構成さえ理解していれば手動でパーティションを切って/をマウントするファイルシステムをBtrfsにすれば自動的にサブボリュームまで切って整えてくれる。

ZFSの話

Btrfsの話をするためにZFSの話を引き合いに出したい人がいるとしたら、それはSolaris上のZFSの話をしたいのか、ZFSのportの話をしたいのか、あるいはLinux上でのZFS実装の話をしたいのか明らかにしてもらう必要がある。

例えばBtrfsよりもZFSが優れていると考えており、ZFSを使うためにSolarisや、(portの存在する)FreeBSDを選択するというのは悪いことではないと私は思う。 同様に、HAMMER2を使いたいがためにDragonflyBSDを使うのも良いだろう。

しかしこの場合、SolarisやFreeBSDがLinux以上に、少なくとも同等に優れているかということを考えなければならない。 宗教戦争をしたいわけではないので私は詳しくは言及しないが、少なくとも私自身はこれを肯定しない。 ZFSを使うためにLinuxを他のOSと引き換えることは、私にはできない。

Linux上でのZFSの話をするとまた別の問題が出てくる。 Linux上のZFSコードの質が十分に高くない(FAT32やNTFSよりは高いが)という問題と、有名なライセンスの問題だ。 少なくともLinusはZFSのコードを受け入れるつもりはないし、だからこそZFSは問題を抱えている。

現実的かつ具体的な問題としては

  • ZFSはカーネルモジュールとして動作するため、Linuxカーネルとの間に縛りがある
  • ZFS自体は最新カーネルに追従しているが、そこにはラグがあるためZFSがシステムの更新を妨げうる
  • 少なくともカーネルを更新するごとにZFSをビルドし直す必要がある
  • ZFSは放置はされていないが十分にメンテナンスもされておらず、将来的に不安を抱えている

そもそもLinux上でZFSを使う明確なメリットに乏しい。LinuxのファイルシステムではなくともXFSはLinux上で優れた性能を発揮し、あえて使用する動機がちゃんと存在する。 一方ZFSモジュール自体はLinux上のネイティブ機能としてZFSを使うことを目標にしてはいる(つまりXFSやJFSのように)が、実際にはその水準になく、(VFATやHFSのように)他のシステムが使うファイルシステムをLinuxでも取り扱うためのモジュールに過ぎないと見ることができる。 ZFSを取り扱う他のシステムがある(SolarisやFreeBSDなどを使っている)なら分かるが、LinuxだけのためにZFSを使うのはいささか時代遅れである。

この「時代遅れ」というのは前述の通り、Ext4, Btrfs, XFSに関しては登場してから今に至るまですごいスピードで改良されており、ZFSはそのスピードについてこれていないので、ZFSが魅力的に映ったのは昔の話だ、という意味だ。 また、UFSを使っていたFreeBSDの場合、モダンなファイルシステムを採用したいという動機が強く、ZFSを採用し開発するメリットが明確にあった(FreeBSDのUFSはXFS同様に当初とは全くの別物だが)。一方、Linuxの場合Ext4やBtrfsが選べる状態でZFSを採用しなければならない動機に乏しい。

また、一般的にレスキューシステムやインストールイメージはZFSを含まないため、ZFSにしてしまうと救出が難しくなる。

個人的にはOpenSolarisやOpenIndianaでZFSを使ったり、HAMMER2を使いたいがためにDragonflyBSDを運用したりしていたが、「Btrfsとどっちが優れているか」は不毛な議論だとしても、「Linux上でのZFSとLinux上でのBtrfsどちらが優れているか」という話になると割と論を待たないレベルで差が開いている。