Arch Linux 下 Btrfs 使用小记
BTRFS 介绍
{B|Bug}-TRee File System 是一个支持{写时复制|Copy on Write}、子卷快照、数据校验、透明压缩等多种高级功能的现代文件系统。 - 写时复制 - 修改不是原地覆盖,而是先写入到空白区域,再修改指针,可保证数据一致性。 - 支持{快速复制|reflink},简单来说就是副本之间尽量共用数据块,通过 CoW 机制只需额外存储改动部分。 - 可以避免对统一区域的反复写入,对闪存友好。 - 快照和子卷地位相当,也可以修改和创建快照。有人认为将其称作“分支”更加贴切。 - 数据校验可以发现 silent corruption 等数据损坏。 - 发现损坏时,会尝试用通过校验的备份修复,失败则报告 IO 错误。 - 默认配置中,数据只存一份,元数据复制两份1。 - 重要数据需要在其他设备上备份2。 - 透明压缩: - 通过牺牲一定的 CPU 时间,减少实际写入硬盘的数据,提高存储容量与 IO 速度。 - 文件系统内部行为,用户无感。 - 顾名思义,该文件系统使用数据结构 B 树维护元数据。 - 为了支持其先进的快照功能,实际使用的是一种能够高效复制的改进版。3 - 原理可以理解为一种懒惰思想,即共用各副本的相同部分。 - 这就是有垃圾回收的可持久化多叉平衡树,太裤辣!
BTRFS 数据损坏测试
安装软件包 btrfs-progs。
用文件虚拟出一块硬盘。之后你可以手动编辑该文件模拟数据损坏,看看会发生什么。
1 | |
安装 BTRFS
笔者的分区方案(终端推荐 cfdisk 工具): -
/dev/nvme0n1p1 分配 260MB,挂载于
/efi。(引导模式为 x64 UEFI) -
/dev/nvme0n1p2 分配剩余空间,格式化为 btrfs 文件系统。 -
无交换分区。 - 此方案也适用于双系统,注意设备标签可能不同。
设计子卷布局
- 个人认为,尽量不要在需要拍摄快照的子卷里面放子卷,用挂载或软链接代替。
- 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存放容器,@opt存放自包含软件,我理解这些东西独立于系统存在,不需要一起快照。
分卷并挂载
格式化并分卷:
1 | |
挂载:
1 | |
关于挂载选项的说明: - -o
选项表示指定挂载选项,后面紧跟的参数是个字符串,所以注意不要输入空格(或者用双引号括起来)
- subvol 指定挂载的子卷。(或 subvolid 通过 ID
指定) - noatime 禁用文件访问时间更新,可以减少写入量,对
SSD 友好。 - 在一个有快照的子卷内访问文件会更糟,会导致元数据 B
树复制(这原本是懒惰的)。 - chattr +A
可以对特定的文件和目录单独禁用访问时间更新。没试过。 -
nodiratime 被 noatime 蕴含,没必要。 -
compress=zstd:3 指定压缩算法为
zstd,并指定压缩级别为 \(3\)。 - zstd 压缩又快又好。 - 默认级别是
\(3\),没测试过哪个级别最快。 -
ssd 会自动检测并优化,不需要加该选项。 -
discard=async 自 kernel 6.2 起已经是默认选项。
安装必要软件包
需要安装 btrfs-progs 包,不然装 linux
内核时会报错。
1 | |
Snapper 快照管理
1 | |
snap-pac 是一个 pacman
hook,用来在每次更改软件包前后自动创建快照。
然后创建快照配置。 1
2
3sudo snapper -c root create-config /
sudo btrfs subvolume delete /.snapshots
sudo mount -o noatime,compress=zstd:3,subvol=@snapshots /dev/nvme0n1p2 /.snapshots --mkdir
修改
/lib/systemd/system/snapper-timeline.timer,设置创建快照频率
修改配置文件
/etc/snapper/configs/root,设置保留的快照数量
开启 Snapper 自动快照和自动清理的后台服务:
1 | |
从快照恢复
推荐安装 grub-btrfs 包,这个包可以在 grub
界面里列出快照。
以下为手动操作。如果系统崩了启动不了,就用启动盘;如果没崩,重启后生效。
1 | |
交换文件与休眠
创建并启用交换文件(8 GB): 1
2btrfs filesystem mkswapfile --size 8G /swap/swapfile
swapon /swap/swapfile
据说推荐的交换空间大小大概是 \(\max(M/2,\sqrt{M})+M\cdot H\) 其中 \(M\) 为物理内存大小(GB),\(H\) 表示是否使用休眠功能。
编辑 fstab,追加:
/swap/swapfile none swap defaults 0 0
以在开机时自动启用交换文件。
配置休眠
运行 1
btrfs inspect-internal map-swapfile -r /swap/swapfile
然后创建
/etc/tmpfiles.d/hibernation.conf,写入如下内容,其中: -
${offset} 为上述命令的输出 - /dev/nvme0n1p2
为交换文件所在分区 - image_size 指定生成的镜像大小,0
表示尽可能压缩
# Path Mode UID GID Age Argument
w /sys/power/resume_offset - - - - ${offset}
w /sys/power/image_size - - - - 0
w /sys/power/resume - - - - /dev/nvme0n1p2
编辑 /etc/mkinitcpio.conf,修改 HOOKS=()
一行,添加 resume(必须在 udev
后面),示例:
HOOKS=(base udev autodetect microcode modconf kms keyboard keymap consolefont block filesystems resume fsck)
然后
1 | |
其他
GUI 快照管理软件: 1
sudo pacman -S btrfs-assistant
参考资料
Suspend and hibernate - ArchWiki
ArchLinux 安装及 Snapper 和 btrfs-grub 的使用