背景
Bcachefs は LInuxカーネル 6.7 からサポートされた Copy-On-Write (CoW) のファイルシステムである。 Bcachefs は、従来のLinuxでサポートされていた "bcache" をベースとしており、堅牢性と信頼性に加えて、多くの機能をサポートしていることで注目を浴びている。
目的
手元の Raspberry Pi 4 Model B (Raspberry Pi 4) で Bcachefs のドキュメントに従って実行することで、挙動や機能の概要を把握する。
実行環境
Raspberry Pi 4 は microSDカード経由でRaspberry Pi OSを起動させる。
ここで使用するRaspberry Pi 4のスペックについて、必要な情報だけ抜粋したものを下記に示す。
項目 | Raspberry Pi 4 |
---|---|
CPU | Cortex-A72 (ARM v8) 1.5GHz |
メモリ | 4GB LPDDR4-3200 |
OS | Raspberry Pi OS Lite (Mar 15th 2024) |
Linux kernel | v6.9-rc31 |
bcachefs-tools | version v0.1-nogit |
fio | fio-3.33 |
micro SD card | KTHN-MW016G |
USB 3.0 (1) | USM32GU |
USB 3.0 (2) | SP032GBUF3B02V1K |
USB 2.0 (1) | USM32GR |
ケース | 陽極酸化アルミニウム製ヒートシンクケース |
シングルドライブでの実験
単一のUSBフラッシュドライブのみに対して bcachefsを使用してみる。
ディスクパーティション /dev/sda
を bcachefs でフォーマットするには、 bcacahefs format
コマンドを実行する。
pi@raspberrypi:~$ sudo bcachefs format /dev/sda
External UUID: 87cb6bbc-c417-4d66-8053-a96e07bc1dc2
Internal UUID: 19bbba4a-3a3d-4f72-974d-dcaedc54bbdb
Device index: 0
Label:
Version: unwritten_extents
Oldest version on disk: unwritten_extents
Created: Wed Apr 17 05:53:46 2024
Sequence number: 0
Superblock size: 816
Clean: 0
Devices: 1
Sections: members
Features: new_siphash,new_extent_overwrite,btree_ptr_v2,extents_above_btree_updates,btree _updates_journalled,new_varint,journal_no_flush,alloc_v2,extentssCompat features:
Options:
block_size: 512 B
btree_node_size: 256 KiB
errors: continue [ro] panic
metadata_replicas: 1
data_replicas: 1
metadata_replicas_required: 1
data_replicas_required: 1
encoded_extent_max: 64.0 KiB
metadata_checksum: none [crc32c] crc64 xxhash
data_checksum: none [crc32c] crc64 xxhash
compression: [none] lz4 gzip zstd
background_compression: [none] lz4 gzip zstd
str_hash: crc32c crc64 [siphash]
metadata_target: none
foreground_target: none
background_target: none
promote_target: none
erasure_code: 0
inodes_32bit: 1
shard_inode_numbers: 1
inodes_use_key_cache: 1
gc_reserve_percent: 8
gc_reserve_bytes: 0 B
root_reserve_percent: 0
wide_macs: 0
acl: 1
usrquota: 0
grpquota: 0
prjquota: 0
journal_flush_delay: 1000
journal_flush_disabled: 0
journal_reclaim_delay: 100
nocow: 0
members (size 64):
Device: 0
UUID: 6b8b7038-fa14-4c21-8d1e-00b0cac0adf6
Size: 28.9 GiB
Bucket size: 256 KiB
First bucket: 0
Buckets: 118296
Last mount: (never)
State: rw
Label: (none)
Data allowed: journal,btree,user
Has data: (none)
Discard: 0
Freespace initialized: 0
initializing new filesystem
going read-write
initializing freespace
mounted version=unwritten_extents opts=noinodes_use_key_cache
kernel が bcachefs をサポートしている場合、従来のファイルシステムと同様に mount
コマンドにより指定したマウントポイントに bcachefs をマウントすることができる。
pi@raspberrypi:~$ sudo mount -t bcachefs /dev/sda /mnt/
ここで、Flexible I/O tester (FIO) による簡易な読み書きパフォーマンスのベンチマークを取ってみる。
I/O サイズを 1 MB で順次書き込みをするようなジョブファイル write1.fio
を使って書き込み帯域幅を確認する。
// 1: [global] ioengine=libaio size=4G invalidate=1 direct=1 verify=0 randrepeat=0 unlink=0 sync=0 ; 順次読み込みの場合は rw=read rw=write bs=1M time_based=1 [job] name=write_bandwidth_test ; ブロックデバイスでの測定の場合は file=/dev/sda directory=/mnt ramp_time=2 runtime=5m numjobs=4 group_reporting=1 iodepth=1
上記の測定結果(bcachefs上のファイルにアクセスした場合)に加えて、ブロックデバイスに直接アクセスした場合の書き込み/読み込み帯域幅を図示すると次のようになった。
この結果だけ見ると、Bcachefs によるオーバーヘッドが大きく見えてしまうが、"データと"ファイル"へのアクセスを比較しているため、これを性能の優劣をつけることはできない。 本来であれば、測定結果の妥当性の確認もしておきたいが、それは本記事の目的から外れるため割愛する。
暗号化
Bcachefsでは、認証付暗号化方式 AEAD の暗号化 (ChaCha20/Poly1305) をサポートしている。 これにより、ファイルシステム全体に対して暗号化することができ、スーパーブロックを除くすべてのメタデータが暗号化される。
暗号化を使用して Bcachefs でフォーマットするには、bcachefs format
コマンドに --encrypted
オプションを追加する。
このとき、passphrase の入力が求められる。
pi@raspberrypi:~$ sudo bcachefs format --encrypted /dev/sda
Enter passphrase:
Enter same passphrase again:
External UUID: 0ac05aa8-9b50-48fd-9bfc-95a016a0e74e
Internal UUID: 5da9ad34-0907-4eee-a2c4-e99378bb1719
Device index: 0
Label:
Version: unwritten_extents
Oldest version on disk: unwritten_extents
Created: Mon Apr 15 00:08:25 2024
Sequence number: 0
Superblock size: 880
Clean: 0
Devices: 1
Sections: members,crypt
Features: new_siphash,new_extent_overwrite,btree_ptr_v2,extents_above_btree_updates,btree _updates_journalled,new_varint,journal_no_flush,alloc_v2,extentssCompat features:
Options:
block_size: 512 B
btree_node_size: 256 KiB
errors: continue [ro] panic
metadata_replicas: 1
data_replicas: 1
metadata_replicas_required: 1
data_replicas_required: 1
encoded_extent_max: 64.0 KiB
metadata_checksum: none [crc32c] crc64 xxhash
data_checksum: none [crc32c] crc64 xxhash
compression: [none] lz4 gzip zstd
background_compression: [none] lz4 gzip zstd
str_hash: crc32c crc64 [siphash]
metadata_target: none
foreground_target: none
background_target: none
promote_target: none
erasure_code: 0
inodes_32bit: 1
shard_inode_numbers: 1
inodes_use_key_cache: 1
gc_reserve_percent: 8
gc_reserve_bytes: 0 B
root_reserve_percent: 0
wide_macs: 0
acl: 1
usrquota: 0
grpquota: 0
prjquota: 0
journal_flush_delay: 1000
journal_flush_disabled: 0
journal_reclaim_delay: 100
nocow: 0
members (size 64):
Device: 0
UUID: 466c5ef5-893c-4b7a-8781-0dcc2d2734ed
Size: 28.9 GiB
Bucket size: 256 KiB
First bucket: 0
Buckets: 118272
Last mount: (never)
State: rw
Label: (none)
Data allowed: journal,btree,user
Has data: (none)
Discard: 0
Freespace initialized: 0
暗号化された bcachefs ファイルシステムはロック状態となっているため、そのままではマウントすることはできない。
pi@raspberrypi:~$ sudo mount -t bcachefs /dev/sda /mnt/
mount: /mnt: mount(2) system call failed: Required key not available.
dmesg(1) may have more information after failed mount system call.
pi@raspberrypi:~$ sudo dmesg | grep bcachefs
[ 599.228656] bcachefs (cd0e560a-0916-4b26-9db8-5d4aa60500e4): error requesting encryption key: ENOKEY
暗号化された bcachefs ファイルシステムは、 bcachefs unlock
コマンドによってロック解除することができる。
このとき、暗号化で使用した passphrase の入力が求められる。
pi@raspberrypi:~$ sudo bcachefs unlock /dev/sda
Enter passphrase:
これにより、暗号化キーがカーネル内のキーリングに追加される。
ただし、ここからマウントなどする場合には、キーをセッションに手動でリンクする必要があるらしい。(または、unlock
のときに-k session
オプションを追加する)
Re: Mounting a encrypted disk: Fatal error: Required key not available - Martin Steigerwald
pi@raspberrypi:~$ sudo keyctl link @u @s
これによって、現在のセッションで暗号化された bcachefs が利用 (マウント) できるようになる。
pi@raspberrypi:~$ sudo mount -t bcachefs /dev/sda /mnt/
ここで、FIO による簡易な読み書きパフォーマンスのベンチマークを取ってみる。 I/O サイズを 1 MB で順次書き込みをするようなジョブファイル write1.fioを使って書き込み帯域幅を確認する。
今回の測定では、暗号化機能を有効にした場合の書き込み帯域幅のオーバーヘッドは微小であった。 一方で、USB3.0(1)と(2)の読み込み帯域幅は25%程度の低下が見られた。また、USB2.0(1)の低下が微小であった。オーバーヘッドが微小であるのは、ストレージデバイスへのアクセスで律速しているケースと考えられる、
また、この機能を有効化していない場合、ブロックデバイス経由でbcachefsにあるファイルの名前が確認できたが、
pi@raspberrypi:~$ sudo xxd -a /dev/sda | grep -E "job\.[0-3]\.0"
002801d0: 086a 6f62 2e30 2e30 0600 0000 0000 0000 .job.0.0........
0210fb70: 0210 0000 0000 0000 086a 6f62 2e33 2e30 .........job.3.0
03f19970: 0310 0000 0000 0000 086a 6f62 2e32 2e30 .........job.2.0
05d0c190: 0410 0000 0000 0000 086a 6f62 2e31 2e30 .........job.1.0
0ed40440: 0000 0020 0000 0000 086a 6f62 2e30 2e30 ... .....job.0.0
0ed40640: 0210 0000 0000 0000 086a 6f62 2e33 2e30 .........job.3.0
0ed40840: 0410 0000 0000 0000 086a 6f62 2e31 2e30 .........job.1.0
0ed40870: 086a 6f62 2e32 2e30 0000 0000 0000 0000 .job.2.0........
この機能を有効にしている場合、ブロックデバイス経由でbcachefsにあるファイルの名前を確認することはできなかった。
pi@raspberrypi:~$ sudo xxd -a /dev/sda | grep -E "job\.[0-3]\.0"
pi@raspberrypi:~$
圧縮
Bcachefsでは、データをエクステント単位による圧縮 (gzip、lz4、zstd) をサポートしている。
圧縮レベルは、0
~ 15
を指定することができる。
さらに、コマンド bcachefs setattr
によって特定のファイル/ディレクトリに対しても有効となっている。
また、rebalanceスレッドによって別のアルゴリズムによるデータを圧縮/再圧縮することもできる。
lz4
で圧縮、zstd
でバックグラウンド圧縮するためには、bcachefs format
コマンドに --compression
と--background_compression
オプションを追加する。
pi@raspberrypi:~$ sudo bcachefs format --compression=lz4 --background_compression=zstd /dev/sda
Bcachefs を /mnt
以下にマウントする。
pi@raspberrypi:~$ sudo mount -t bcachefs /dev/sda /mnt/
ここで、FIO による簡易な読み書きパフォーマンスのベンチマークを取ってみる。 I/O サイズを 1 MB で順次書き込みをするようなジョブファイル write1.fioを使って書き込み帯域幅を確認する。
また、この機能による効果を確認するために、巨大なテキストファイル群 (linux-6.9-rc4.tar) をコピーしてみる。
pi@raspberrypi:~$ ls -l /mnt
total 1454330
-rw-r--r-- 1 root root 1489233920 Apr 18 05:44 linux-6.9-rc4.tar
drwx------ 2 root root 0 Apr 18 05:42 lost+found
pi@raspberrypi:~$ df /dev/sda
Filesystem 1K-blocks Used Available Use% Mounted on
/dev/sda 27615550 662787 26538105 3% /mnt
pi@raspberrypi:~$ sync
pi@raspberrypi:~$ df /dev/sda
Filesystem 1K-blocks Used Available Use% Mounted on
/dev/sda 27615550 397492 26799319 2% /mnt
対象のファイル群はファイルサイズ1.4GBであったが、bcachefsによる圧縮(lz4)の効果により 662KB の使用量まで抑えられている。 また、rebalanceスレッドによってzstdへと再圧縮されており、400KBまで減っていることが分かった。
マルチドライブでの実験
bcachefs はマルチデバイス2に対応しているファイルシステムである。
ここでは、Raspberry Pi OSがそれぞれのUSBフラッシュドライブを次のように認識している場合である。
デバイスファイル | USBフラッシュドライブ | 書き込み帯域幅(暫定) | 読み込み帯域幅(暫定) |
---|---|---|---|
/dev/sda |
USB3.0(1) | 11.8MB/s | 109MB/s |
/dev/sdb |
USB3.0(2) | 15.4MB/s | 110MB/s |
/dev/sdc |
USB2.0(1) | 4.1MB/s | 26.6MB/s |
ストライピング
bcachefsでは、複数のドライブを指定したときはストライピング(RAID0)として扱う。
pi@raspberrypi:~$ sudo bcachefs format /dev/sda /dev/sdb
External UUID: 3e548aa6-9b4e-4465-988c-86f6c40c6348
Internal UUID: b95602d7-ce7c-47e0-b7bf-26b1300a9b5e
Device index: 1
Label:
Version: unwritten_extents
Oldest version on disk: unwritten_extents
Created: Thu Apr 18 20:25:12 2024
Sequence number: 0
Superblock size: 872
Clean: 0
Devices: 2
Sections: members
Features: new_siphash,new_extent_overwrite,btree_ptr_v2,extents_above_btree_updates,btree _updates_journalled,new_varint,journal_no_flush,alloc_v2,extents_across_btree_nodes
Compat features:
Options:
block_size: 512 B
btree_node_size: 256 KiB
errors: continue [ro] panic
metadata_replicas: 1
data_replicas: 1
metadata_replicas_required: 1
data_replicas_required: 1
encoded_extent_max: 64.0 KiB
metadata_checksum: none [crc32c] crc64 xxhash
data_checksum: none [crc32c] crc64 xxhash
compression: [none] lz4 gzip zstd
background_compression: [none] lz4 gzip zstd
str_hash: crc32c crc64 [siphash]
metadata_target: none
foreground_target: none
background_target: none
promote_target: none
erasure_code: 0
inodes_32bit: 1
shard_inode_numbers: 1
inodes_use_key_cache: 1
gc_reserve_percent: 8
gc_reserve_bytes: 0 B
root_reserve_percent: 0
wide_macs: 0
acl: 1
usrquota: 0
grpquota: 0
prjquota: 0
journal_flush_delay: 1000
journal_flush_disabled: 0
journal_reclaim_delay: 100
nocow: 0
members (size 120):
Device: 0
UUID: 16aa5679-4832-4197-bb0c-ea8004dac946
Size: 28.9 GiB
Bucket size: 256 KiB
First bucket: 0
Buckets: 118272
Last mount: (never)
State: rw
Label: (none)
Data allowed: journal,btree,user
Has data: (none)
Discard: 0
Freespace initialized: 0
Device: 1
UUID: 175843da-3652-40a1-ab42-13aed32fdc7f
Size: 28.9 GiB
Bucket size: 256 KiB
First bucket: 0
Buckets: 118296
Last mount: (never)
State: rw
Label: (none)
Data allowed: journal,btree,user
Has data: (none)
Discard: 0
Freespace initialized: 0
initializing new filesystem
going read-write
initializing freespace
マルチドライブによる bcachefs のマウントには、 :
によってブロックデバイス名を指定する必要がある。
pi@raspberrypi:~$ sudo mount -t bcachefs /dev/sda:/dev/sdb /mnt/
/mnt
は /dev/sda
と/dev/sdb
の2つのブロックデバイスから構成されているので、合計領域もそれらの総和となっている。
pi@raspberrypi:~$ df -h /mnt/
Filesystem Size Used Avail Use% Mounted on
/dev/sda:/dev/sdb 53G 1.5M 52G 1% /mnt
ここで、FIO による簡易な読み書きパフォーマンスのベンチマークを取ってみる。 I/O サイズを 1 MB で順次書き込みをするようなジョブファイル write1.fioを使って書き込み帯域幅を確認する。
レプリケーション
2台のドライブによるレプリケーション(RAID1)するには、bcachefs formatコマンドに --replicas
オプションを追加する。
pi@raspberrypi:~$ sudo bcachefs format /dev/sda /dev/sdb --replicas=2
External UUID: de438111-fb04-402f-a8c9-a2a2033df85d
Internal UUID: 07de9a56-0613-40a9-a6e3-5361ea4165f7
Device index: 1
Label:
Version: unwritten_extents
Oldest version on disk: unwritten_extents
Created: Thu Apr 18 07:10:24 2024
Sequence number: 0
Superblock size: 872
Clean: 0
Devices: 2
Sections: members
Features: new_siphash,new_extent_overwrite,btree_ptr_v2,extents_above_btree_updates,btree _updates_journalled,new_varint,journal_no_flush,alloc_v2,extentss
Compat features:
Options:
block_size: 512 B
btree_node_size: 256 KiB
errors: continue [ro] panic
metadata_replicas: 2
data_replicas: 2
metadata_replicas_required: 1
data_replicas_required: 1
encoded_extent_max: 64.0 KiB
metadata_checksum: none [crc32c] crc64 xxhash
data_checksum: none [crc32c] crc64 xxhash
compression: [none] lz4 gzip zstd
background_compression: [none] lz4 gzip zstd
str_hash: crc32c crc64 [siphash]
metadata_target: none
foreground_target: none
background_target: none
promote_target: none
erasure_code: 0
inodes_32bit: 1
shard_inode_numbers: 1
inodes_use_key_cache: 1
gc_reserve_percent: 8
gc_reserve_bytes: 0 B
root_reserve_percent: 0
wide_macs: 0
acl: 1
usrquota: 0
grpquota: 0
prjquota: 0
journal_flush_delay: 1000
journal_flush_disabled: 0
journal_reclaim_delay: 100
nocow: 0
members (size 120):
Device: 0
UUID: 28f83018-915d-4423-986c-32ad8f361fde
Size: 28.9 GiB
Bucket size: 256 KiB
First bucket: 0
Buckets: 118272
Last mount: (never)
State: rw
Label: (none)
Data allowed: journal,btree,user
Has data: (none)
Discard: 0
Freespace initialized: 0
Device: 1
UUID: 3b4b848a-89f2-48d2-96de-556b69f15cb4
Size: 28.9 GiB
Bucket size: 256 KiB
First bucket: 0
Buckets: 118296
Last mount: (never)
State: rw
Label: (none)
Data allowed: journal,btree,user
Has data: (none)
Discard: 0
Freespace initialized: 0
initializing new filesystem
going read-write
initializing freespace
mounted version=unwritten_extents opts=metadata_replicas=2,data_replicas=2,noinodes_use_key_cache
Bcachefs を /mnt
以下にマウントする場合には複数のブロックデバイスを指定する。
pi@raspberrypi:~$ sudo mount /dev/sda:/dev/sdb /mnt/
ここで、FIO による簡易な読み書きパフォーマンスのベンチマークを取ってみる。 I/O サイズを 1 MB で順次書き込みをするようなジョブファイル write1.fioを使って書き込み帯域幅を確認する。
キャッシュ
bcachefs ではデバイスにラベルを付与することができる。 このラベルによってグループ化された特定のデバイスに特定にアクションを優先させたりすることで、ストレージデバイスの特性を活かすことができる。
bcachefs では、読み書きのターゲットとして、フォアグラウンドでの書き込み先 --forground_target
、バックグラウンドで書き戻す先 --background_target
、読み込み時にキャッシュとして使う --promote_target
と設定することができる。
例えば、アクセス速度が速いUSB3.0(1) /dev/sda
とUSB3.0(2) /dev/sdb
に ssd
ラベル、遅いUSB2.0(/dev/sdc
)には hdd
ラべルを付与することで、上記のターゲットのルールは次のように設定することができる。[^3]
pi@raspberrypi:~$ sudo bcachefs format \
--label=ssd.ssd1 /dev/sda \
--label=hdd.hdd1 /dev/sdb \
--label=hdd.hdd2 /dev/sdc \
--foreground_target=ssd \
--promote_target=ssd \
--background_target=hdd
Bcachefs を /mnt以下にマウントする場合には複数のブロックデバイスを指定する。
pi@raspberrypi:~$ sudo mount /dev/sda:/dev/sdb /mnt/
そこで、いくつかのパターンで FIO による簡易な読み書きパフォーマンスのベンチマークを取ってみる。 I/O サイズを 1 MB で順次書き込みをするようなジョブファイル write1.fioを使って書き込み帯域幅を確認する。
パターン | foreground_target |
promote_target |
background_target |
---|---|---|---|
2 SSDs | USB3.0(1) + USB3.0(2) | USB3.0(1) + USB3.0(2) | USB2.0(1) |
1 SSD | USB3.0(1) | USB3.0(1) | USB3.0(1) + USB2.0(1) |
Slow 1 SSD | USB2.0(1) | USB2.0(1) | USB3.0(1) + USB3.0(2) |
この測定でも、フォアグラウンドでの読み書きを高速なデバイスに割り当て、そうでないデバイスをバックグラウンドに割り当てたほうがパフォーマンスが良い傾向が見られた。
変更履歴
- 2024/04/23: 記事公開
参考文献
- Bcachefs ドキュメント
- Arch Linux による Bcachefs ドキュメント
- Gentoo Linux による Bcachefs ドキュメント