BTRFS 入坑记

被学长传教了……
关于 BTRFS
B-Tree File System 是一个支持写时复制(CoW)、子卷快照、数据校验、透明压缩等多种高级功能的现代文件系统。
- 写时复制(Copy on Write, CoW)
- 修改不是原地覆盖,而是先写入到空白区域,再修改指针,可保证数据一致性。
- 支持快速复制(reflink),因为 CoW 机制所以后续只需要存储对副本的改动。
- 避免对统一区域的反复写入,对 SSD 友好。
- 快照和子卷地位相当,也可以修改和创建快照。有人认为将其称作“分支”更加贴切。
- 数据校验可以发现 silent corruption 等数据损坏。
- 透明压缩:
- 通过牺牲一定的 CPU 时间,减少实际写入硬盘的数据,提高存储容量与 IO 速度。
- 文件系统内部行为,用户无感。
- 顾名思义,该文件系统使用数据结构 B 树维护元数据。
- 为了支持其先进的快照功能,实际使用的是一种能够高效复制的改进版。[3]
- 原理可以理解为一种懒惰思想,因而会共用各副本的相同部分。
- 这就是有垃圾回收的可持久化多叉平衡树,太裤辣!
试用 btrfs(雾)
安装软件包 btrfs-progs
。
用文件虚拟出一块硬盘,用来测试 btrfs 在各种情况下的表现[4]。
1 | # 创建一个镜像 |
为新系统安装 BTRFS
记录了笔者为全新安装的 Arch Linux 配置 btrfs 文件系统的过程,全过程戳我。
参考资料[5]
笔者的分区方案:
/dev/nvme0n1p1
分配 260MB,挂载于/efi
。/dev/nvme0n1p2
分配剩余空间,格式化为 btrfs 文件系统。- 使用交换文件而非交换分区。
1 | mkfs.btrfs /dev/nvme0n1p2 |
设计子卷布局
- 个人认为,尽量不要在需要拍摄快照的子卷里面放子卷,用挂载或软链接代替。
- btrfs 中的子卷使用目录结构组织,表现像文件夹。
- 虽然看上去子卷可以嵌套,但其实本质上并不是,快照时并不会和嵌套的子卷一起快照。
例如可以建立@A/@B
这样的子卷结构。然后给@A
拍摄快照@a
,会发现@a/@B
并不是子卷,而是无法写入的普通目录。
回滚时需要处理这些嵌套的子卷,比较麻烦。
- 文件系统的根子卷比较特殊,无法从快照恢复,因此选择将
@
子卷挂载于/
。 - 最终决定采用所谓的“扁平布局”,如下:
子卷 | 挂载点 |
---|---|
@ | / |
@snapshots | /.snapshots |
@swap | /swap |
@home | /home |
@root | /root |
@var_log | /var/log |
@var_cache | /var/cache |
@var_tmp | /var/tmp |
@docker | /var/lib/docker |
@opt | /opt |
说明:
@
子卷存放操作系统与安装的软件,@snapshots
存放系统快照。@swap
存放交换文件。包含交换文件的子卷无法快照,故单独分卷。/home/用户名
和/root
是普通用户和 root 用户的主目录,分卷可在快照回滚时保留其中的用户数据。/var/log
存放日志,不应该快照。/var/cache
和/var/tmp
存储缓存和临时文件,不需要快照。@docker
存放 docker 数据,@opt
存放自包含软件,我理解这些东西独立于系统存在,不需要一起快照。
分卷并挂载
分区:
1 | btrfs subvolume create /mnt/@{,snapshots,swap,home,root,var_{cache,log,tmp},docker,opt} |
挂载:
1 | mount -o noatime,compress=zstd:3,subvol=@ /dev/nvme0n1p2 /mnt |
-o
选项表示指定挂载选项,后面的部分不能有空格。subvol=
指定挂载的子卷。noatime
禁用文件访问时间更新,可以减少写入量,对 SSD 友好。- 在一个有快照的子卷内访问文件会更糟,会导致元数据 B 树复制(这原本是懒惰的)。
chattr +A
可以对特定的文件和目录单独禁用访问时间更新。
nodiratime
被noatime
蕴含,没必要。compress=zstd:3
指定压缩算法为zstd
,并指定压缩级别为。 - zstd 压缩又快又好。
- 默认级别是
,没测试过哪个级别最快。
ssd
会自动检测并优化,不需要加该选项。discard=async
自 kernel 6.2 起已经是默认选项。
安装必要软件包
需要安装 btrfs-progs
包,不然装 linux
内核时会报错。
1 | pacstrap -K /mnt btrfs-progs |
安装 Snapper[6] 并配置
1 | sudo pacman -S snapper |
然后创建快照配置。
1 | sudo snapper -c root create-config / |
修改 /lib/systemd/system/snapper-timeline.timer
,设置创建快照频率
1 | [Timer] |
修改配置文件 /etc/snapper/configs/root
,设置保留的快照数量
1 | TIMELINE_MIN_AGE="3600" |
开启Snapper自动快照和自动清理
1 | sudo systemctl enable --now snapper-{timeline,cleanup}.timer |
从快照恢复
如果系统崩了启动不了,就用启动盘。
如果没崩,重启后生效。
1 | # 挂载 btrfs 分区 |
交换文件与休眠
创建并启用交换文件:
1 | btrfs filesystem mkswapfile --size 8G /swap/swapfile |
推荐的交换空间大小大概是
虽然新电脑 32G 内存,但我感觉旧电脑 8GB 不打游戏够用,赌一手
编辑 fstab
,追加:
1 | /swap/swapfile none swap defaults 0 0 |
以在开机时自动启用交换文件。
配置休眠
参考 Arch Wiki[7]。
运行
1 | btrfs inspect-internal map-swapfile -r /swap/swapfile |
然后创建 /etc/tmpfiles.d/hibernation.conf
,写入如下内容,其中偏移量为上述命令的输出:
1 | # Path Mode UID GID Age Argument |
编辑 /etc/mkinitcpio.conf
,修改 HOOKS=()
一行,添加 resume
(必须在 udev
后面)(以下仅为示例):
1 | HOOKS=(base udev autodetect microcode modconf kms keyboard keymap consolefont block filesystems resume fsck) |
文件备份的 321 原则,本地一份,云端一份,算上原件共三份。 ↩︎
- Title: BTRFS 入坑记
- Author: Berrylium
- Created at : 2024-10-31 17:03:08
- Updated at : 2025-03-29 23:40:48
- Link: https://berrylium0078.github.io/2024/10/31/arch-btrfs/
- License: This work is licensed under CC BY-NC-SA 4.0.
Comments