新しいファイルシステム Bcachefs
自宅サーバーを再構築するにあたり、以前利用していたZFSからBcachefsに乗り換えました。
私が利用しているArch Linuxの場合、ZFSは通常のリポジトリ経由では取得できず、またカーネルを更新する際にZFSが対応しているか事前に調査が必要など、管理面でのコストが発生しており多少不満を感じていました。Bcachefsはカーネルにマージされているので、その不満の解消が期待できます。
はじめに
この記事は下記のユーザーガイドと手元で構築したBcachefsの実際の挙動をもとに書いています。
新たにBcachefsを始めたい人や、管理の仕方について知りたい人を対象としています。
uname -sr
Linux 6.10.8-arch1-1
フォーマット
Bcachefsでは事前にフォーマットを行う必要があります。単体のディスクに加え、複数のディスクをまとめて利用することも可能です。
実例がないと解説がしにくいため、先にコマンドを書いておきます。8TBx8のストレージと2TBのSSDでのキャッシュで構築します。レプリカ数は3です。
bcachefs format \
--errors=ro \
--replicas=3 \
--label=hdd.hdd1 /dev/disk/by-id/ata-WDC_WD80EAZZ-00BKLB0_WD-CA0TX67K \
--label=hdd.hdd2 /dev/disk/by-id/ata-WDC_WD80EAZZ-00BKLB0_WD-CA0UGRAK \
--label=hdd.hdd3 /dev/disk/by-id/ata-WDC_WD80EAZZ-00BKLB0_WD-CA0UGYXK \
--label=hdd.hdd4 /dev/disk/by-id/ata-WDC_WD80EAZZ-00BKLB0_WD-CA0UHDKK \
--label=hdd.hdd5 /dev/disk/by-id/ata-WDC_WD80EAZZ-00BKLB0_WD-CA0URTJK \
--label=hdd.hdd6 /dev/disk/by-id/ata-WDC_WD80EAZZ-00BKLB0_WD-CA0USJGK \
--label=hdd.hdd7 /dev/disk/by-id/ata-WDC_WD80EAZZ-00BKLB0_WD-CA0UT8RK \
--label=hdd.hdd8 /dev/disk/by-id/ata-WDC_WD80EAZZ-00BKLB0_WD-CA2KGR5L \
--durability=0 --discard \
--label=nvme.cache1 /dev/disk/by-id/nvme-ADATA_LEGEND_800_2N052L2HSH2C \
--foreground_target=nvme \
--promote_target=nvme \
--background_target=hdd
--errors=ro
エラー時の挙動を指定
ファイルシステムでエラーが発生した時の挙動を設定します。定期的にステータスを確認するのであれば continue
が良いかもしれません。
オプション | 動作 |
---|---|
continue |
エラーをログに出力し何もしない |
ro |
読み取り専用モードに切り替え |
panic |
システムを停止 |
--replicas=[n]
レプリカ数を指定
レプリカ数を指定します。このオプションに指定した数から1を引いたディスクまで同時故障してもデータ損失がないことが保証されます。
レプリケーションの挙動はRAID10相当 同時故障に注意
RAIDzはパリティを分散して全てのディスクに書き込む手法を採用していますが、Bcachefsでは --replicas
に指定された数だけ同じデータを別のディスクに書き込む手法を採用しています。
2台のディスクが同時に故障したとしてもRAIDz2やRAID6の場合はデータは必ず復元できますが、Bcachefsで --replicas=2
を指定した場合は運が悪いとデータ損失が発生します。同時故障について考慮する必要がある場合は、想定同時故障HDD + 1の数をReplicasに指定するのが良いでしょう。
BcachefsでもRAIDz2やRAID6相当のパリティを分散する手法は開発中ですが、2024年09月現在対象のオプションの説明文では (DO NOT USE YET)
と記載されています。
bcachefs format --help
// ...
--erasure_code Enable erasure coding (DO NOT USE YET)
参考:
--label=hdd.hdd1 /dev/disk
ディスクを指定
ラベル付きで物理ディスクを指定します。管理上の都合から /dev/disk/by-id/
を利用していますが、 /dev/sda
等直接ブロックデバイスを指定しても構いません。
ラベルは .
区切りでグループ名の指定が可能です。上記の例の場合は hdd
グループの hdd1
といった形で指定されます。グループ名は後述するターゲットでキャッシュの宛先に指定することができます。
物理ディスクサイズが異なっていても問題ありません。Bcachefsは常により空き容量の多いデバイスを優先するため、全てのディスクが同じ割合で埋まるように調節して書き込みされます。
--durability=0 --discard
SSDキャッシュ用設定
キャッシュのみに利用するSSDのために、 --durability=0
で信頼性が不要で永続的なストレージとして利用しないことを定義します。また、SSD向けにTRIM/discardを有効化します。
また、--durability
オプションを使ってそのディスクの信頼性を明示的にBcachefsに伝えることができます。例えば、Linux上からは1つに見えるブロックデバイスがハードウェアRAIDで2台の冗長性を持っている場合 --durability=2
としておくことでBcachefsがレプリカ数を調整してくれます。
bcachefs format
コマンドはディスク指定の順番に注意
やや複雑な点ですが、 bcachefs format
コマンドには順番の概念が存在します。 --durability
はデフォルトで1ですが、このオプションを指定して以降に追加されたデバイスは0として追加されます。
下記のように、複数のデバイスをフォーマットする場面を考えてみましょう。デフォルトでは暗黙的に --durability=1
が指定されており、3つのHDDは durability=1
として扱われます。その後 --durability=0
を指定すると、後続のディスクは durability=0
として扱われます。
bcachefs format
--errors=ro
( --durability=1 (defaultで暗黙的に指定) )
--label hdd.hdd1 /dev/sda (durability=1)
--label hdd.hdd2 /dev/sdb (durability=1)
--label hdd.hdd3 /dev/sdc (durability=1)
--durability=0
--label ssd.cache0 /dev/nvme0 (durability=0)
--label ssd.cache1 /dev/nvme1 (durability=0)
--durability=2
--label hdd.hdd4 /dev/raida (durability=2)
--label hdd.hdd5 /dev/raidb (durability=2)
前述のSSDキャッシュの説明とあわせ、SSDキャッシュを追加するときは必ず --durability=0
を指定した後にデバイスを追加しましょう。
--foreground_target
他 キャッシュ等の設定
ターゲットを指定します。それぞれ下記のような動作をします。基本的に background_target
にはHDD、 foreground_target
と promote_target
にはSSDを指定するのが良いでしょう。同じデバイスも指定できます。
オプション | 動作 |
---|---|
--foreground_target |
新規データの優先書き込み先 |
--promote_target |
読み取りデータのキャッシュ先 再度同じファイルにアクセスされたときに高速化 |
--background_target |
データの長期保存先 foreground_targetからバックグラウンドで徐々に書き込まれる |
マウント
/mnt/ada
にマウントすると仮定します。マウントに必要なUUIDは External UUID
を利用します。 format
時に表示されるものをメモしておくか、 sudo bcachefs show-super [メンバのブロックデバイス]
で再表示できます。
mount.bcachefs UUID=729347e7-24a2-4f80-93ad-885e74f4fd8e /mnt/ada
メンバを構成する一部のブロックデバイスを指定することでもマウントできます。
mount -t bcachefs /dev/sda /mnt/ada
上記のコマンドそのままでは、デバイスが破損したりブロックデバイスが足りない場合は下記のエラーがdmesgに出力されマウントに失敗します。
bch2_fs_open() bch_fs_open err opening /dev/sda: insufficient_devices_to_start
bch2_mount() error: insufficient_devices_to_start
その場合は -o degraded
を追加するとデータ損失がない場合に限りマウントできます。また、 -o very_degraded
を追加するとデータ損失があるかもしれない状況でも無理矢理マウントできます。
mount.bcachefs UUID=729347e7-24a2-4f80-93ad-885e74f4fd8e -o degraded /mnt/ada
/etc/fstab
記載例
UUID=729347e7-24a2-4f80-93ad-885e74f4fd8e /mnt/ada bcachefs defaults,nofail 0 0
障害復旧
ディスクの破損などが発生した場合の交換手順について簡単に記載しておきます。
-o degraded
をつけてマウントする
Degradedモードでマウントをします。
mount.bcachefs UUID=729347e7-24a2-4f80-93ad-885e74f4fd8e -o degraded /mnt/ada
問題のあるデバイスを削除する
/dev/sde
が故障したと仮定します。パスで削除・インデックスで削除の2通りの方法が利用できます。コマンドの実行にはかなり時間がかかります。 screen
などを利用して切断に備えるのが良いでしょう。
Linux上からブロックデバイスが見える場合は下記の方法で削除できます。
# パスで削除
bcachefs device remove /dev/sde
ブロックデバイスがLinux上から消滅している場合はデバイスのindexを用いて削除することもできます。
# 生きているデバイスからメタデータを取得し問題のあるデバイスのIndexを確認
bcachefs show-super /dev/sda
// ...
Device: 4
Label: hdd5 (5) # かっこ内がIndex
UUID: 4ff2352d-b962-4d67-8bd9-d272cc55b601
Size: 7.28 TiB
# 削除 Indexでの削除にはマウント先のパスが必要
bcachefs device remove 5 /mnt/ada
デバイスを交換し追加する
交換元と交換先のSATAポートが同じならブロックデバイスのパスは変わらないはずです。
bcachefs device add --label=hdd.hdd5 /mnt/ada /dev/sde
不足しているレプリカを再作成
この状態ではレプリカが不足しているため、再作成が必要です。
bcachefs data rereplicate
TIPS: HDDを交換せず別のデバイスにレプリカを再作成する
RAIDzやRAID5, 6とは異なり、破損したHDDに存在するデータを他のHDDの空き容量に書き込むこともできます。すぐに障害のあるHDDを交換することができない場合などに有効です。上記と同じく /dev/sde
が故障したと仮定します。
下記コマンドを実行し /dev/sde
をReadOnlyに設定します。その後、 evacuate
コマンドでその中にあるデータを退避させることが可能です。
bcachefs device set-state /dev/sde readonly
bcachefs device evacuate /dev/sde
SubvolumeとSnapshot
Bcachefsはサブボリューム単位でのスナップショット作成をサポートしています。サブボリュームやスナップショットはLinux上から通常のディレクトリのように見えます。
サブボリュームの作成
bcachefs subvolume create
コマンドを利用します。また、検証用にファイルを touch
しておきます。
cd /mnt/ada
bcachefs subvolume create sub0
touch /mnt/ada/sub0/hello.world
スナップショットの作成
サブボリュームを指定してスナップショットを作成します。作成したスナップショットはLinux上からは通常のディレクトリのように見えます。
bcachefs subvolume snapshot /mnt/ada/sub0 /mnt/ada/sub0-20240906
ファイルがスナップショット先にも存在することが確認できます。
ls /mnt/ada/sub0*
/mnt/ada/sub0:
hello.world
/mnt/ada/sub0-20240906:
hello.world
作成したスナップショットは新たなサブボリュームとして振る舞うため、必要に応じてスナップショットのスナップショットを作成することも可能です。
サブボリューム・スナップショットの削除
サブボリュームやスナップショットを削除するために bcachefs subvolume delete
コマンドを利用する他、 rm -rf
や rmdir
を用いて削除することができます。
bcachefs subvolume delete /mnt/ada/sub0
オプションの指定はフォーマット後も可能
Bcachefsにはさまざまなオプションが指定できます。オプションは対応するタイミングや単位で切り替えが可能になっています。
例えば、 --data_replicas
はフォーマット時のみならずマウント時や実行時、さらにinode単位で設定することができます。下記はマウント済みの /mnt/ada
にある very_important
フォルダのレプリカ数を5に設定するコマンドです。
bcachefs setattr --data_replicas=5 --recursive /mnt/ada/very_important
このコマンドを使うと、次回以降 /mnt/ada/very_important
フォルダへの書き込みは5台のディスクに分散されて行われます。すでに存在するデータも対象にしたい場合は、下記のコマンドを実行します。
bcachefs data rereplicate
利用可能なオプションとタイミングについてはページ最下部に載せてあります。
終わりに
構築し利用を開始した段階では、Bcachefsは十分に実用可能な段階に達していると感じています。ユーザーランドのツールである bcachefs
コマンドは出力や使い勝手の点でやや荒削りな部分を感じますが、この辺りは徐々に改善されるでしょうし、一旦構築をしてしまえば利用には困りません。
一方で、柔軟なオプション設定に対して情報量が少ないのがネックに感じました。ディスクの交換といったよくあるワークロードでも、日本語はもちろん英語でも情報が限られているように感じます。ユーザーガイドやWiki、Redditなどの情報を読み込み、オペレーションをする人がきちんと理解をしていないと現段階ではうまく扱うことができないのではないかな?と感じています。
この記事が初めてBcachefsを使う方の参考になれば幸いです。
オプション一覧
2024年09月現在、ユーザーマニュアルに記載されているものの一覧です。
オプション/機能 | フォーマット時 | マウント時 | 実行時 | inode単位 | 説明 |
---|---|---|---|---|---|
block_size | ✓ | ファイルシステムのブロックサイズ(デフォルト4k) | |||
btree_node_size | ✓ | Btreeノードサイズ(デフォルト256k) | |||
errors | ✓ | ✓ | ✓ | ファイルシステムエラー時のアクション | |
metadata_replicas | ✓ | ✓ | ✓ | メタデータのレプリカ数 | |
data_replicas | ✓ | ✓ | ✓ | ✓ | ユーザーデータのレプリカ数 |
replicas | ✓ | metadata_replicasとdata_replicasの両方のエイリアス | |||
metadata_checksum | ✓ | ✓ | ✓ | メタデータ書き込みのチェックサムタイプ | |
data_checksum | ✓ | ✓ | ✓ | ✓ | データ書き込みのチェックサムタイプ |
compression | ✓ | ✓ | ✓ | ✓ | 圧縮タイプ |
background_compression | ✓ | ✓ | ✓ | ✓ | バックグラウンド圧縮タイプ |
str_hash | ✓ | ✓ | ✓ | ✓ | 文字列ハッシュテーブルのハッシュ関数 |
metadata_target | ✓ | ✓ | ✓ | ✓ | メタデータ書き込みの優先ターゲット |
foreground_target | ✓ | ✓ | ✓ | ✓ | フォアグラウンド書き込みの優先ターゲット |
background_target | ✓ | ✓ | ✓ | ✓ | バックグラウンドでデータを移動するターゲット |
promote_target | ✓ | ✓ | ✓ | ✓ | 読み取り時にデータをコピーするターゲット |
erasure_code | ✓ | ✓ | ✓ | ✓ | イレイジャーコーディングの有効化 |
inodes_32bit | ✓ | ✓ | ✓ | 新しいinode番号を32ビットに制限 | |
shard_inode_numbers | ✓ | ✓ | ✓ | 新しいinode番号の上位ビットにCPU idを使用 | |
wide_macs | ✓ | ✓ | ✓ | 完全な128ビット暗号化MACを保存(デフォルト80) | |
inline_data | ✓ | ✓ | ✓ | インラインデータエクステントの有効化(デフォルトon) | |
journal_flush_delay | ✓ | ✓ | ✓ | 自動ジャーナルコミット前の遅延(ミリ秒、デフォルト1000) | |
journal_flush_disabled | ✓ | ✓ | ✓ | sync/fsyncでのジャーナルフラッシュの無効化 | |
journal_reclaim_delay | ✓ | ✓ | ✓ | 自動ジャーナル再利用前の遅延(ミリ秒) | |
acl | ✓ | ✓ | POSIX ACLの有効化 | ||
usrquota | ✓ | ✓ | ユーザークォータの有効化 | ||
grpquota | ✓ | ✓ | グループクォータの有効化 | ||
prjquota | ✓ | ✓ | プロジェクトクォータの有効化 | ||
degraded | ✓ | データが縮退した状態でのマウントを許可 | |||
very_degraded | ✓ | データが欠落した状態でのマウントを許可 | |||
verbose | ✓ | マウント/リカバリ中の追加デバッグ情報 | |||
fsck | ✓ | マウント中にfsckを実行 | |||
fix_errors | ✓ | fsck中にエラーを自動修復 | |||
ratelimit_errors | ✓ | fsck中のエラーメッセージをレート制限 | |||
read_only | ✓ | 読み取り専用モードでマウント | |||
nochanges | ✓ | ジャーナル再生でも書き込みを発行しない | |||
norecovery | ✓ | ジャーナルを再生しない(非推奨) | |||
noexcl | ✓ | デバイスを排他モードで開かない | |||
version_upgrade | ✓ | ディスク上のフォーマットを最新バージョンにアップグレード | |||
discard | ✓ | ✓ | discard/TRIMサポートの有効化 |
Discussion