CentOS 上的 Btrfs:使用 Loopback

简介

btrfs 文件系统多年来一直困扰着 Linux 社区,它提供了令人惊叹的功能和能力,但从未获得普遍赞誉。Btrfs 或许更值得耐心等待,因为其承诺的功能超越了所有同类产品,为其赢得了具有巨大影响力的直言不讳的支持者。然而,没有人可以争辩说 btrfs 尚未完成,许多功能非常新,并且常见功能的稳定性问题仍然存在。

btrfs 的大多数预期目标已经实现。然而,红帽以著名的方式从其 7.4 版本中削减了对 btrfs 的持续支持,并且自那时以来,允许该代码在其反向移植的内核中停滞不前。Fedora 项目宣布他们打算采用 btrfs 作为其发行版变体的默认文件系统,这似乎是一种并置。SUSE 多年来一直维护 btrfs 对其自身发行版和更广泛社区的支持。

对于用户而言,btrfs 最令人向往的功能是透明压缩和快照;这些功能稳定,并且相对容易作为表层添加到库存 CentOS(及其同类产品)中。管理员进一步被可调整的校验和、擦洗以及扩大以及(令人惊讶地)缩小文件系统映像的能力所吸引,而一些高级 btrfs 主题(即,重复数据删除、RAID、ext4 转换)对于最小的环回使用而言并非真正重要。systemd init 包还依赖于 btrfs,其中包括 machinectlsystemd-nspawn。尽管有这些功能,但仍有许多使用模式不直接适用于 btrfs。它对大多数数据库和许多其他具有不兼容 I/O 的程序不友好,应该谨慎对待。

CentOS 兼容的启用 btrfs 内核的两个最容易访问的提供商是 El Repo Mainline 和 Oracle Unbreakable Enterprise Kernel (UEK),但每个选项在支持和功能方面都有重要的限制。Oracle 的内核未实现用于强制执行文件系统完整性的最新 btrfs 校验和标准,并且从 CentOS 的角度来看,Oracle 还存在其他组织问题。El Repo Mainline 具有最新功能,但不鼓励使用它,并且不受支持。当前的 Fedora 内核似乎也可以在 CentOS 8 上运行,但是这些安装在删除库存内核组件方面更具侵入性。用户将面临霍布森选择,具体取决于他们对高级功能或商业支持的需求。

尽管如此,凭借功能强大的内核,当在默认 XFS 主机文件系统上运行时,可以通过环回挂载(在一定程度上会降低性能)在任何 CentOS、RedHat 或 Oracle Linux 操作系统上轻松启用这些功能。在这些功能不可或缺的情况下,它们可以防止迁移到 Solaris、FreeBSD 甚至 SUSE,在这些系统中,高级存储功能更为常见。

我将在此处参考我过去关于Linux 版 ZFS的文章,以阐明和翻译这两个流行的文件系统之间的术语。不必理解 ZFS 即可掌握对 btrfs 的讨论,但是对比可能会有所帮助。

安装

与 CentOS 安装最兼容的 btrfs 启用内核的两个提供商在支持和功能方面提供了截然不同的体验。评估这两个内核的安装可能是最方便的,下面的发送/接收部分假设它们的功能都存在。

CentOS 7 在操作系统安装程序中(作为“技术预览”)确实支持原生 btrfs 作为自定义选项,但是已从 CentOS 8 安装程序中删除,因此此处不再赘述。所有示例均使用 CentOS 8;CentOS 7 用户可能更喜欢 UEK。

要安装 Oracle UEK,请添加以下文件作为 /etc/yum.repos.d/uek-olx.repo(对于 CentOS 7,将“ol8/OL8”更改为“ol7/OL7”)

[ol8_UEKR6]
name=Latest Unbreakable Enterprise Kernel Release 6 for Oracle Linux $releasever ($basearch)
baseurl=https://yum.oracle.com/repo/OracleLinux/OL8/UEKR6/$basearch/
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-oracle
gpgcheck=1
enabled=1

加载相关仓库的 GPG 密钥,如 Oracle 的说明中(有些不正确地)描述

 curl -o /etc/pki/rpm-gpg/RPM-GPG-KEY-oracle \
	https://yum.oracle.com/RPM-GPG-KEY-oracle-ol8

为了自动安装 UEK,请执行以下操作(如果您没有 C 编译器,请省略 devel 包)

yum install kernel-uek btrfs-progs btrfs-progs-devel

我添加了选项 --disablerepo=AppStream--disablerepo=BaseOS--disablerepo=extras,以强制 dnf 通过限制性防火墙工作,仅从 Oracle 的存储库中拉取

dnf	--disablerepo=AppStream \
	--disablerepo=BaseOS \
	--disablerepo=extras \
	install kernel-uek btrfs-progs btrfs-progs-devel

此命令的结果如下

Last metadata expiration check: 0:04:38 ago on Tue 15 Sep 2020 11:43:34 AM CDT.
Dependencies resolved.
================================================================================
 Package           Arch   Version                               Repo       Size
================================================================================
Installing:
 btrfs-progs       x86_64 5.4.0-1.el8                           ol8_UEKR6 869 k
 btrfs-progs-devel x86_64 5.4.0-1.el8                           ol8_UEKR6  52 k
 kernel-uek        x86_64 5.4.17-2011.6.2.el8uek                ol8_UEKR6  60 M
Upgrading:
 linux-firmware    noarch 999:20200124-999.4.git1eb2408c.el8    ol8_UEKR6 100 M

Transaction Summary
================================================================================
Install  3 Packages
Upgrade  1 Package

Total download size: 161 M
Is this ok [y/N]: y
Downloading Packages:
(1/4): btrfs-progs-devel-5.4.0-1.el8.x86_64.rpm  21 kB/s |  52 kB     00:02    
(2/4): btrfs-progs-5.4.0-1.el8.x86_64.rpm       225 kB/s | 869 kB     00:03    
(3/4): kernel-uek-5.4.17-2011.6.2.el8uek.x86_64 2.1 MB/s |  60 MB     00:29    
(4/4): linux-firmware-20200124-999.4.git1eb2408 1.1 MB/s | 100 MB     01:27    
--------------------------------------------------------------------------------
Total                                           1.8 MB/s | 161 MB     01:30
Latest Unbreakable Enterprise Kernel Release 6  3.0 MB/s | 3.1 kB     00:00    
Importing GPG key 0xAD986DA3:
 Userid     : "Oracle OSS group (Open Source Software group) "
 Fingerprint: 76FD 3DB1 3AB6 7410 B89D B10E 8256 2EA9 AD98 6DA3
 From       : /etc/pki/rpm-gpg/RPM-GPG-KEY-oracle
Is this ok [y/N]: y
Key imported successfully
Running transaction check
Transaction check succeeded.
Running transaction test
Transaction test succeeded.
Running transaction
  Preparing        :                                                        1/1 
  Upgrading        : linux-firmware-999:20200124-999.4.git1eb2408c.el8.no   1/5 
  Installing       : btrfs-progs-5.4.0-1.el8.x86_64                         2/5 
  Installing       : btrfs-progs-devel-5.4.0-1.el8.x86_64                   3/5 
  Running scriptlet: kernel-uek-5.4.17-2011.6.2.el8uek.x86_64               4/5 
  Installing       : kernel-uek-5.4.17-2011.6.2.el8uek.x86_64               4/5 
  Running scriptlet: kernel-uek-5.4.17-2011.6.2.el8uek.x86_64               4/5 
  Cleanup          : linux-firmware-20191202-97.gite8a0f4c9.el8.noarch      5/5 
  Running scriptlet: kernel-uek-5.4.17-2011.6.2.el8uek.x86_64               5/5 
  Running scriptlet: linux-firmware-20191202-97.gite8a0f4c9.el8.noarch      5/5 
  Verifying        : btrfs-progs-5.4.0-1.el8.x86_64                         1/5 
  Verifying        : btrfs-progs-devel-5.4.0-1.el8.x86_64                   2/5 
  Verifying        : kernel-uek-5.4.17-2011.6.2.el8uek.x86_64               3/5 
  Verifying        : linux-firmware-999:20200124-999.4.git1eb2408c.el8.no   4/5 
  Verifying        : linux-firmware-20191202-97.gite8a0f4c9.el8.noarch      5/5 
Installed products updated.

Upgraded:
  linux-firmware-999:20200124-999.4.git1eb2408c.el8.noarch                      

Installed:
  btrfs-progs-5.4.0-1.el8.x86_64           btrfs-progs-devel-5.4.0-1.el8.x86_64
  kernel-uek-5.4.17-2011.6.2.el8uek.x86_64

Complete!

对于手动安装,请直接从存储库中拉取最新的 UEK 和关联的 RPM

https://yum.oracle.com/repo/OracleLinux/OL8/UEKR6/x86_64/

安装后,UEK 将自身配置为默认启动内核。另请注意,在上面的 dnf 会话中安装了一个新的固件包(如果卸载 UEK,请准备将其降级回 CentOS 版本)。

UEK 存在两个主要问题,无论是总体上还是从 CentOS 的角度来看。

首先,Oracle UEKR6(当前)太旧,无法使用 btrfs 的最新校验和功能(在下一节中说明)。

其次,CentOS 上的 UEK 提供付费支持,但仅在将整个系统转换为 Oracle Linux 后。加载 UEK 不会触发此转换。此外,转换过程对于 Centos 8 似乎已损坏。尝试运行 centos2ol.sh 转换器脚本时,它会因需要 python2 的错误而停止。从 AppStream 安装 python2 后,脚本失败并显示消息:“您似乎正在运行不受支持的发行版。如需帮助,请发送电子邮件至 <ksplice-support_ww@oracle.com>。”检查脚本,仅允许 CentOS 版本 5、6 和 7,Oracle 的网站上也暗示了缺少 CentOS 8 支持(“centos2ol.sh 可以将您的 CentOS 6 和 7 系统转换为 Oracle Linux”)。由于 CentOS 8 平台已经上市一年多了,因此 Oracle 的脚本似乎严重过时。Oracle 是否支持 CentOS 8 平台令人怀疑。

El Repo 项目之前维护了最终红帽反向移植的 btrfs 源代码的历史存档。虽然这个闲置版本从未从测试中发布并且已被删除,但最新的 btrfs 内核模块在他们的其他软件包中可用。

El Repo 将他们的 Mainline 称为“最后的手段内核”,这通常是用于反向移植硬件驱动程序的开发人员工具。它碰巧包含具有最新功能的 btrfs 模块,这些模块将完美地与此处介绍的所有功能一起工作。要加载它,请从 El Repo Mainline 存储库获取并安装以下文件(或安装 yum 存储库本身的条目)

rpm -Uvh \
	kernel-ml-5.8.5-1.el8.elrepo.x86_64.rpm \
	kernel-ml-core-5.8.5-1.el8.elrepo.x86_64.rpm \
	kernel-ml-modules-5.8.5-1.el8.elrepo.x86_64.rpm

安装应按以下输出进行

Verifying...                          ################################# [100%]
Preparing...                          ################################# [100%]
Updating / installing...
   1:kernel-ml-core-5.8.5-1.el8.elrepo################################# [ 33%]
   2:kernel-ml-modules-5.8.5-1.el8.elr################################# [ 67%]
   3:kernel-ml-5.8.5-1.el8.elrepo     ################################# [100%]

完成后,重新启动,一个新的红帽内核(提到 Oopta)应出现在 Grub 菜单中。选择省略 UEK 的 El Repo Mainline 内核用户可能应该加载 Oracle 的 btrfs-progs,因为这将允许用户空间维护。

下面列出的 Fedora 内核似乎可以在 CentOS 上运行,但是应更加谨慎地安装 Fedora 组件,因为以升级模式安装时,它们可能会删除 CentOS 提供的库存内核包(Mainline 和 UEK 都保持库存内核不变)。在这种情况下,使用 Fedora yum 存储库可能不安全。

rpm -Uvh \
 kernel-5.9.0-0.rc8.20201007git7575fdda569b.30.fc34.x86_64.rpm \
 kernel-core-5.9.0-0.rc8.20201007git7575fdda569b.30.fc34.x86_64.rpm \
 kernel-modules-5.9.0-0.rc8.20201007git7575fdda569b.30.fc34.x86_64.rpm

rpm -qa | grep ^kernel | sort

安装应按以下输出进行

Verifying...                          ################################# [100%]
Preparing...                          ################################# [100%]
Updating / installing...
   1:kernel-core-5.9.0-0.rc8.20201007g################################# [ 17%]
   2:kernel-modules-5.9.0-0.rc8.202010################################# [ 33%]
   3:kernel-5.9.0-0.rc8.20201007git757################################# [ 50%]
Cleaning up / removing...
   4:kernel-4.18.0-193.el8            ################################# [ 67%]
   5:kernel-modules-4.18.0-193.el8    ################################# [ 83%]
   6:kernel-core-4.18.0-193.el8       ################################# [100%]

kernel-5.9.0-0.rc8.20201007git7575fdda569b.30.fc34.x86_64
kernel-core-5.9.0-0.rc8.20201007git7575fdda569b.30.fc34.x86_64
kernel-ml-5.8.5-1.el8.elrepo.x86_64
kernel-ml-core-5.8.5-1.el8.elrepo.x86_64
kernel-ml-modules-5.8.5-1.el8.elrepo.x86_64
kernel-modules-5.9.0-0.rc8.20201007git7575fdda569b.30.fc34.x86_64
kernel-tools-4.18.0-193.el8.x86_64
kernel-tools-libs-4.18.0-193.el8.x86_64
kernel-uek-5.4.17-2011.6.2.el8uek.x86_64

也可以在 Fedora 中找到 btrfs-progs 包,如果存在 Oracle 的包,它也会擦除它们。

rpm -Uvh \
 btrfs-progs-5.7-4.fc33.x86_64.rpm \
 btrfs-progs-devel-5.7-4.fc33.x86_64.rpm \
 libbtrfs-5.7-4.fc33.x86_64.rpm \
 libbtrfsutil-5.7-4.fc33.x86_64.rpm

安装应按以下输出进行

Verifying...                          ################################# [100%]
Preparing...                          ################################# [100%]
Updating / installing...
   1:libbtrfsutil-5.7-4.fc33          ################################# [ 17%]
   2:libbtrfs-5.7-4.fc33              ################################# [ 33%]
   3:btrfs-progs-5.7-4.fc33           ################################# [ 50%]
   4:btrfs-progs-devel-5.7-4.fc33     ################################# [ 67%]
Cleaning up / removing...
   5:btrfs-progs-devel-5.4.0-1.el8    ################################# [ 83%]
   6:btrfs-progs-5.4.0-1.el8          ################################# [100%]

El Repo Mainline 的问题在于缺乏支持,甚至积极劝阻使用它。Fedora 可能是一个“更最后的手段”,因为它可能会删除 CentOS 内核包,除非非常小心地安装。最新的SUSE 内核也可能引起人们的兴趣,但这并非旨在用于 CentOS,并且在此处未尝试过。构建自定义内核可能会提供最佳结果,但代价是失去任何和所有支持。

Btrfs 创建和校验和

btrfs 文件系统创建过程中固有的选择是块级校验和,用于记录和强制执行所有内容的完整性和准确性。在最近的历史中,此选择仅限于 CRC32C 算法,该算法容易发生冲突,并且不合理地适用于重复数据删除(此处未涵盖)。

校验和的选择受到关注的两个内核的限制,并且选项非常鲜明。

Btrfs 最近实现了新的校验和,其详细信息在 man 5 btrfs 中描述,此处摘录用于“3.5GHz intel CPU”(如手册页中所述)

摘要 周期/4KiB 比率
CRC32C 1700 1.00
XXHASH 2500 1.44
SHA256 105000 61
BLAKE2b 22000 13

上面的哈希对于密码应用程序的技术用户可能很熟悉。NSA 的 SHA256 算法通常具有 CPU 原语的支持,以实现快速处理,并且对于重复数据删除具有足够的抗冲突性。XXHASH 算法声称在避免哈希冲突方面比 CRC32C 有了很大的改进,并且对吞吐量的影响最小。

上述哈希选择的问题在手册页中明确指出:“要挂载此类文件系统,[内核]必须也支持校验和。” 必须理解,当前的 Oracle UEKR6 仅支持 CRC32C,并且不会挂载使用任何其他哈希函数创建的 btrfs 文件系统,即使它分发的用户空间工具既允许又鼓励这样做

对于本文档的其余部分,以下挂载点将被假定为我们的主 btrfs 文件系统。请创建此挂载点以遵循所有进一步的示例

mkdir /bvault

以下 shell 代码片段演示了用户空间选项与内核校验和限制的对比

for CSUM in crc32c xxhash sha256 blake2
do fallocate -l 50G /home/CALDRON.BTRFS

   mkfs.btrfs --csum="$CSUM" /home/CALDRON.BTRFS

   mount -o loop /home/CALDRON.BTRFS /bvault
   umount /bvault

   rm -v /home/CALDRON.BTRFS
done

我在上面选择了名称“caldron”,以表彰 ZFS zpool “tank”,作为一个更清晰的名称,用于我们正在调制的特性混合,我偶尔会将其称为“后备存储”。在 Oracle UEK 上,只有 CRC32 挂载尝试会成功,而 El Repo Mainline 将运行该脚本,所有校验和类型都不会出错。

上面 fallocate 的使用灵感来自之前关于 btrfs 环回设备的文章,该文章为本次讨论奠定了基础。环回挂载通常用于历史上写入光盘介质的 .ISO 映像。请注意,环回文件系统挂载通常很快,但在 fsync() 调用过多时可能会受到影响

Oracle UEK 是最新的 5.4.17 内核,但不够新,无法支持 CRC32C 以外的任何内容,这可以从 man 5 btrfs 中了解到:“自内核 5.5 以来,还有三个[校验和],它们在速度和强度方面具有不同的特性和权衡。” 当甚至 Oracle 都忽略了反向移植新功能时,我们开始理解红帽的观点。

当运行 UEK 时,这是新的 btrfs 文件系统上可用的最佳校验和

fallocate -l 50G /home/CALDRON.BTRFS
mkfs.btrfs --csum=crc32c /home/CALDRON.BTRFS
mount -o loop /home/CALDRON.BTRFS /bvault

如果 El Repo Mainline 是活动内核,则可以使用 Oracle 的 mkfs.btrfs 实现的任何校验和。

从 ZFS 的角度来看,这一切都非常原始。ZFS 允许动态选择任何校验和/哈希函数,以应用于任何文件系统对象。在任何情况下,SHA256 可能是那些渴望极高数据完整性并愿意放弃支持的人的首选。

透明压缩

三种压缩类型可以应用于 btrfs 文件系统中的目录或文件对象。可用的类型按优先级为:zstdlzozlibnone。这些压缩属性的分配作为 btrfs “元数据”维护,内核将在写入内容时执行文件压缩。

关于 btrfs 压缩设置的一些背景知识和具体信息

  • zstd - 由 Facebook 贡献的代码,允许指定介于 1 到 11 之间的数值选择器,以控制内核应用的文件压缩因子。

  • lzo - 侧重于性能,不允许可调选项。

  • zlib - 使用传统的 gzip 算法,并允许应用介于 1 到 9 之间的因子。

未指定时,任何可调算法的默认压缩级别为 3。

虽然可以将压缩全局设置为整个已挂载文件系统的挂载选项,但也可以将其应用于特定目录或文件。声明此属性的语法如下

mkdir /bvault/tmp

btrfs property set /bvault/tmp compression zstd

mkdir /bvault/log

btrfs property set /bvault/log compression lzo
btrfs property set /bvault/log compression zlib:9
btrfs property set /bvault/log compression zstd:11

可以使用此语法检查文件系统对象上的当前属性

btrfs property get /bvault/log compression

此命令的结果如下

compression=zstd:11

包含文件和目录对象压缩设置的元数据无法使用 tar 或其他不了解此特殊状态的 btrfs 内部结构的实用程序进行备份。下面的发送/接收部分能够将所有元数据复制到新的 btrfs 文件系统,并且是唯一可以捕获这些隐藏设置的文件移动实用程序。

遗憾的是,btrfs-progs 包中没有报告工具来辨别磁盘上文件的压缩比率。可以使用一种缺乏精细报告的蛮力方法,即在简单的 shell 函数中使用 df 仅报告所需的挂载。

以下 shell 函数将在后面的示例中使用,请注意它。

function ddf { typeset a b IFS=\|; df | while read a
  do [[ -z "$b" ]] && printf '%s\n' "$a"; for b; do
  case "$a" in *"$b"*) printf '%s\n' "$a";; esac; done; done }

对多个 btrfs 文件系统进行了非正式测试,并报告了

ddf test

对于大量二进制数据的副本,出现了以下压缩结果

Filesystem 1K-blocks    Used Available Use% Mounted on
/dev/loop0 52428800  1989740  50009460   4% /test1
/dev/loop1 52428800 19106016  32844480  37% /test2

一个更精细的实用程序以 C 源代码形式提供。“[compsize 程序]接受 btrfs 文件系统上的文件列表,并测量使用的压缩类型和有效压缩比率。有一个补丁添加了对此的支持;目前尚未合并。如果 df 命令在写入文件之前和之后都可用,您可以通过比较 df 命令的输出来大致猜测其压缩大小。”

要使用此精细报告实用程序,假设您可以访问 Linux C 编译器并且能够准备 compsize,请确保您已安装以下软件包

yum install btrfs-progs-devel

在 btrfs 源代码安装后,下载以下内容以进行 C 编译

https://raw.githubusercontent.com/kilobyte/compsize/master/compsize.c https://raw.githubusercontent.com/kilobyte/compsize/master/radix-tree.c https://raw.githubusercontent.com/kilobyte/compsize/master/endianness.h https://raw.githubusercontent.com/kilobyte/compsize/master/kerncompat.h https://raw.githubusercontent.com/kilobyte/compsize/master/radix-tree.h

使用以下命令将这些文件编译为本机二进制文件

cc -Wall -std=gnu90 -I/usr/include/btrfs \
	-g -o compsize compsize.c radix-tree.c

测试程序。请注意下面的同步事件 - 如果没有同步事件,compsize 可能会失败,因为同步事件似乎会触发内核压缩

cp /var/log/messages /var/log/secure /bvault/log
sync
./compsize /bvault/log/*

这些命令的结果如下

Processed 2 files, 15 regular extents (15 refs), 0 inline.
Type       Perc     Disk Usage   Uncompressed Referenced  
TOTAL       17%      316K         1.7M         1.7M       
zstd        17%      316K         1.7M         1.7M

要阅读有关此压缩比率报告程序的文档,请下载手册页

https://raw.githubusercontent.com/kilobyte/compsize/master/compsize.8

使用以下命令读取手册页

# man ./compsize.8

快照

经典 UNIX 系统的管理员经常面临从备份恢复的请求,并且通常由于 tar 的 cron 计划落在关键活动之外且未捕获关键活动,因此无法满足这些请求。每天一次的备份不涵盖在触发的备份周期之间交付、处理和删除的临时数据。

快照是文件系统状态的“即时照片”,创建速度非常快。当文件系统更改块时,快照会保留旧内容,并完全按照其外观进行保存。可以拍摄 btrfs 文件系统的多个快照,并在磁盘空间可用时保留尽可能长的时间。

让我们拍摄一个快照

cp /etc/passwd /etc/group /etc/shadow /bvault/tmp
btrfs subvolume snapshot /bvault \
	/bvault/snapshot-"$(date +%Y%m%d%H%M%S)"

现在,让我们模拟关键内容的丢失以及从快照恢复

rm /bvault/tmp/shadow
ls /bvault/snapshot-*/tmp/shadow

我们看到快照已保留了我们的关键文件

/bvault/snapshot-20200831112752/tmp/shadow

就这么简单。

在 btrfs 中创建的默认快照不是只读对象;可以在其中添加或更改内容

cp /etc/hosts /bvault/snapshot-*/tmp
ls /bvault/snapshot-*/tmp/hosts

快照现在已与这个新文件发生分歧

/bvault/snapshot-20200831112752/tmp/hosts

可以使用 -r 选项创建只读快照。这可能更适合备份,并且发送/接收功能(如下所述)需要只读状态。

在手册页中,有一些关于 noatime 挂载选项的讨论,特别是关于快照的讨论,并且 URL 被提及为扩展讨论的资源。长期以来,已知 noatime 选项可以提高大多数 UNIX 系统上的文件系统性能,并且它在防止快照增长方面对 btrfs 具有额外的意义,在 btrfs 的关键限制(如下所述)中发挥着进一步的作用。

快照是可挂载 btrfs 文件系统的特殊情况;它们是“子卷”,如下所述,它们的删除方式与所有子卷相同

btrfs subvolume delete /bvault/snapshot-*/

发出带有重要但书的回应

Delete subvolume (no-commit): '/bvault/snapshot-20200831112752'

如果在未提交的子卷删除后发生崩溃,则可能在重新启动后出现。要强制提交删除,请使用 -c-C 选项(手册页中解释了区别)。

在 ZFS 中,快照默认是只读的,并且必须采取进一步的步骤才能将快照实例化为读写“克隆”。不幸的是,btrfs 没有为这些功能重用此术语。

调整大小

Btrfs 在增长方面相当不错,并且是少数能够缩小的常见文件系统之一。对于环回挂载,充当“后备存储”的文件必须首先扩展,然后 btrfs 才能识别额外的空间,并且(不幸的是)只有在卸载/重新挂载后才会识别添加的空间。在缩小方面,首先缩小文件系统,然后截断后备存储。与直觉相反,truncate 实用程序是增长或缩小后备存储的最快工具。

要向 caldron 添加十千兆字节,请使用以下命令

truncate -s +10G /home/CALDRON.BTRFS

Btrfs 不会立即在线识别新空间,但在卸载后会识别(请注意,remount 标志不足以促使 btrfs 查看新空间)

umount /bvault
mount -o loop /home/CALDRON.BTRFS /bvault
btrfs filesystem resize max /bvault
ddf bvault

添加的空间出现

Filesystem 1K-blocks Used Available Use% Mounted on
/dev/loop0  62914560 3652  62372796   1% /bvault

上面的 resize max 比历史上始终需要特定数值大小的卷管理器和文件系统(比如 HP-UX VxFS)方便得多。

Btrfs 也可以收缩,并且能够在释放请求的空间之前将内容(文件系统、快照、元数据)移开。正如手册页指出的那样,“...如果设备区域中有超出新末尾的数据,则收缩可能需要很长时间。数据的重新定位需要时间。”

让我们撤回最近添加的空间

btrfs filesystem resize -10G /bvault
umount /bvault
truncate -s -10G /home/CALDRON.BTRFS

毋庸置疑,在尝试任何调整大小事件之前应进行备份,对于减小尺寸尤其如此,在这种情况下,这些实用程序之间的数字必须精确到字节。

让我们确认 vault 在此操作中幸存下来

btrfs check /home/CALDRON.BTRFS

检查返回广泛的状态

Opening filesystem to check...
Checking filesystem on /home/CALDRON.BTRFS
UUID: 5d5b0ada-0ad0-422c-8d91-2cfcc1dee1eb
[1/7] checking root items
[2/7] checking extents
[3/7] checking free space cache
[4/7] checking fs roots
[5/7] checking only csums items (without verifying data)
[6/7] checking root refs
[7/7] checking quota groups skipped (not enabled on this FS)
found 200704 bytes used, no error found
total csum bytes: 4
total tree bytes: 131072
total fs tree bytes: 32768
total extent tree bytes: 16384
btree space waste bytes: 122345
file data blocks allocated: 69632
 referenced 69632

一切安好...

mount -o loop /home/CALDRON.BTRFS /bvault
ddf bvault

...结局圆满

Filesystem 1K-blocks Used Available Use% Mounted on
/dev/loop0  52428800 3652  51887036   1% /bvault

关键限制

在过去 UNIX 时代的经典 FFS 中,文件系统管理员既关心空间,也关心 inode;耗尽其中任何一个都会使事情陷入停顿。

Btrfs 引入了一组新的担忧和行为。数据、元数据和系统都是独立的实体,当它们耗尽时,可能会使活动的 btrfs 文件系统进入只读模式。有关这些方面的信息可以在 btrfs-filesystem 手册页中找到,报告它们的命令如下

btrfs fi df /bvault

空文件系统的示例大小可能是

Data, single: total=1.01GiB, used=25.36MiB
System, DUP: total=32.00MiB, used=16.00KiB
Metadata, DUP: total=256.00MiB, used=2.11MiB
GlobalReserve, single: total=3.25MiB, used=0.00B

历史 UNIX 变体为 root 保留了特定数量的磁盘空间,其他用户无法使用,从而防止了存储危机导致系统无法使用。不幸的是,btrfs 缺乏此类保护,并且陷入只读模式通常是出乎意料的,因为文件系统数据可能在限制范围内。

在上面关于 noatime 挂载选项的先前讨论中,btrfs 手册页中提到的 URL 包括关于 ZFS zpool 的评论,这些 zpool 仅允许消耗 63/64 的空间,从而模拟了历史空间保留。还有进一步的警告,即 btrfs 上的 atime 写入可能会因空间不足错误而失败,从而阻止从只读状态的 btrfs 文件系统中读取数据。在这种情况下,第一个冲动将是使用 noatime 重新挂载。

扩展空间通常是重新获得对只读 btrfs 的控制权以进行清理的答案。对于环回挂载,上面的调整大小工具应该足以进行轻松修复,前提是主机 XFS 文件系统具有可用空间。当 btrfs 原生安装在磁盘上时,稍微缩小其分区可能是明智之举,从而允许 resize max 进行紧急维护。

或者,可以引入配额,但这会带来成本。正如 btrfs-quota 手册页警告的那样,“当配额激活时,它们会影响所有 extent 处理,这会降低性能。” 如果性能损失可以接受,那么有一些方法可以使用配额来强制执行文件系统安全。

ZFS 在过度拥挤时也表现不佳,这可能会导致无法修复的损坏;btrfs 在这方面似乎更强大一些,但仍然会困住粗心大意的人。ZFS 还允许使用 copies= 参数来复制存储的数据,并默认将 copies=2 应用于元数据;上面的 DUP 标签显示 mkfs.btrfs 也做了同样的事情,它始终在旋转介质上这样做,但在 SSD 上则不然。

子卷

过去几十年的红帽/Sistina 为我们带来了卷管理器,类似于 HP-UX 使用的卷管理器,它允许我们超越经典的 MS-DOS 分区,并使用单个文件系统跨越物理磁盘。ZFS 将卷管理器模糊化为“池”,并将文件系统(数据集)溶解到池中,根据需要分散它们,并在需要时重新组合可见性。

在 btrfs 中,根卷吞噬了池,进一步模糊了焦点。

在 btrfs 中创建子卷似乎会创建一个目录

btrfs subvolume create /bvault/foo
btrfs subvolume list /bvault

我们的最后一个命令报告了新的子卷属性

ID 257 gen 23 top level 5 path foo

但是,可以像九头蛇的触手一样将此目录拉出,并使用 subvol 挂载参数在其他位置挂载

mkdir /foo
mount -o loop,subvol=foo /home/CALDRON.BTRFS /foo
ddf bvault foo

我们看到了子卷在其新分配的挂载点上

Filesystem 1K-blocks Used Available Use% Mounted on
/dev/loop0 52428800  3716  51887036   1% /bvault
/dev/loop0 52428800  3716  51887036   1% /foo

移动挂载点很简单

umount /foo
rmdir /foo
mkdir /etc/foo
mount -o loop,subvol=foo /home/CALDRON.BTRFS /etc/foo
ddf bvault foo

比煮熟的芦笋还快,子卷被重新定位了。

Filesystem 1K-blocks Used Available Use% Mounted on
/dev/loop0 52428800  3716  51887036   1% /bvault
/dev/loop0 52428800  3716  51887036   1% /etc/foo

当操作系统已安装在具有过去快照的 ZFS 数据集上时,可以在根数据集/文件系统上触发回滚事件以将其还原,可能撤消失败的补丁会话。在 btrfs 下,启动快照子卷到根目录,然后将损坏的根目录重命名为另一个子卷(或直接删除它),在重新启动时完成相同的效果。SUSE 提供了工具用于此活动。

 

尽管我避免讨论先前以 CentOS 为中心的 Linux 中存在的原生 btrfs,但 Oracle Linux 7 确实为根文件系统提供了完全支持的 btrfs(/boot 仍保留在 XFS 上,将补丁回滚限制为非内核软件包)。在默认安装中,尝试查询根子卷

btrfs subvolume list /

将产生以下列表

ID 257 gen 44412 top level 5 path root
ID 258 gen 44412 top level 5 path home
ID 261 gen 44409 top level 257 path var/lib/machines

btrfs 的环回用户不太可能对复杂的子卷挂载有广泛的需求,但是视角是独特的。与像 ZFS 那样使用自定义工具维护挂载相比,返回 fstab 也很令人愉快。

碎片整理

ZFS 的一个非常令人遗憾的缺点是缺乏碎片整理方法,而 btrfs 提供了碎片整理。

在旋转介质上的环回挂载配置中,主机文件系统可能应该在对“caldron”的内容进行碎片整理之前进行碎片整理。对于 XFS,defrag 工具可以在详细模式下运行时报告重新组织的文件的 inode。如果需要,可以通过首先记录 caldron 的 inode 来确认对 caldron 后备存储执行的 XFS defrag 操作

ls -i /home/CALDRON.BTRFS

这将报告后备存储的 inode

1304021 /home/CALDRON.BTRFS

在具有旋转介质(硬盘驱动器,而非固态驱动器/SSD)的系统上,运行 XFS “文件系统重组器”,并在 /home 中查找目标 inode

xfs_fsr -v

如果您的系统是旋转介质和 SSD 介质的混合体,则仅将非 SSD 文件系统指定给 xfs_fsr

在 caldron 一致的情况下,触发对其所有子卷的碎片整理

btrfs filesystem defragment /bvault -rv
btrfs filesystem defragment /etc/foo -rv

组织问题有时也可以通过 btrfs-balance 来补救,它会重写整个文件系统并保证 btrfs 中的所有块都将被重新分配。平衡通常在添加新驱动器时执行,但对于改进单个设备上的组织也可能很有用。

SSD 设备

闪存存储对 btrfs 提出了特殊的关注,因为闪存介质缺乏传统硬盘驱动器的寿命。闪存分为两个等级,由 MOS “浮栅”晶体管决定:单层单元 (SLC) 和多层单元 (MLC)。商用级闪存普遍采用 SLC 介质,并且通常被认为在每次单元 100,000 次写入后在退化和数据丢失风险之前是可行的。多层单元 (MLC) 介质,通常作为可移动 USB 闪存实现,在介质寿命终止之前仅可进行 5,000 次写入。SLC 介质以数据密度换取寿命,MLC 则相反,以寿命换取密度。

闪存介质可以通过在华氏200度以上的高温下长时间加热进行“修复”(温度越高,所需时间越短)。不幸的是,目前没有常见的闪存设备利用这一特性,即可以使寿命到期的单元恢复活力。

存储控制器嵌入在所有闪存介质中,它们实现了“磨损均衡算法”,将数据从热点文件迁移到很少写入的单元,以努力使整个存储设备寿命均衡。存储控制器通常基于嵌入式 ARM 或 Intel CPU,并且它们的安全性不高

Btrfs 具有一些选项,可以改变写入闪存介质的模式,以努力延长寿命。这些选项作为挂载时标志实现:ssdssd_spread

“[ssd 挂载] 优化利用了轮转设备固有的寻道延迟的缺失。通常可以更快地写入块,并且不会卸载到单独的线程... ssd_spread 挂载选项尝试分配到更大且对齐的未用空间块中,并且在低端 SSD 上可能表现更好。ssd_spread 隐含了 ssd,也启用了所有其他 SSD 启发式方法。”

btrfs 的 SSD 挂载选项并非总是对寿命安全:“在低于 4.14 的旧内核中使用 ssd 挂载选项会对现代 SSD 的可用性和寿命产生负面影响。这在 4.14 中已修复,请参阅此提交以获取更多信息... 在 [Linux 内核] 4.14+ 中,对于非轮转存储,再次安全且推荐使用 ssd 挂载选项。”

挂载在环回设备上的 Btrfs 文件系统可能无法正确检测到主机 XFS 文件系统位于闪存/SSD 上。使用 hpsa 控制器呈现镜像 MO0200FCTRN 固态硬盘的测试表明,ssd 已自动添加到环回挂载选项中。如果您的硬件未被正确检测到,添加此类挂载选项可能会延长性能和寿命。

发送/接收

Btrfs 压缩设置(和其他元数据)在文件或目录移动或复制到 btrfs 文件系统外部时不会保留。大多数备份工具(即 tarrsync)无法保留这些设置。为了防止丢失此 btrfs-property 元数据,btrfs 和 ZFS 都提供了发送/接收作为 [btrfs] 元数据保留的方法。此外,如果需要将校验和从 CRC32C 迁移到更高级的哈希算法(即 XXHASH、SHA256、BLAKE2)并完全保留元数据,这些是唯一可用的工具。

发送操作的最终目的地必须是能够接收此原始数据的 btrfs 文件系统。

btrfs send 操作必须在只读子卷上调用,很可能是为显式移动(元)数据而创建的快照。这在下面进行了说明,并且必须使用能够进行高级 btrfs 校验和的内核来实现

fallocate -l 50G /home/GOBLET.BTRFS
mkfs.btrfs --csum=sha256 /home/GOBLET.BTRFS
mkdir /goblet
mount -o loop /home/GOBLET.BTRFS /goblet

btrfs subvolume snapshot /bvault /bvault/onmyway -r

btrfs send /bvault/onmyway | btrfs receive /goblet

btrfs subvolume snapshot /bvault/foo /bvault/offwego -r

btrfs send /bvault/offwego | btrfs receive /goblet

这些发送/接收操作将保留 btrfs 元数据,包括压缩设置。没有其他工具可以保留这些文件属性。这些工具还具有用于增量备份的选项,表示为快照之间的差异。发送 很可能应该是完整 btrfs 备份策略的一部分。

擦洗

btrfs 写入的每个块,无论是数据、系统还是元数据,都经过校验和计算。这些存储在磁盘上的校验和可以作为树状结构遍历,从而可以验证整个文件系统的正确性。

ZFS 专注于数据冗余源,如果找到正确的冗余形式,它可以静默修复坏块。使用此处介绍的 btrfs 环回方法,数据不是冗余的,btrfs 只能报告和标记校验和失败的数据。用 ZFS 的术语来说,环回 btrfs 意味着“讨厌我们的数据。”

通常会对存储控制器、物理硬盘驱动器、SSD 驱动器、主板固件和 CPU 微代码应用固件更新。例如,HP“ProLiant 支持包”每季度发布时都会这样做,许多竞争对手的服务器平台的打包硬件更新也是如此。这些海量固件更新中存在大量错误机会,校验和/擦洗验证几乎可以在供应商固件故障发生后立即检测到它们。

除此之外,“数据退化是会发生的。” 磁盘上的数据会随着时间的推移而变坏,这归因于多种因素。检测到坏数据总比忽略它要好。

在任何情况下,都应在 btrfs 环回设备上执行擦洗操作,以确保完整性。触发 btrfs 文件系统中所有块校验和的擦洗验证的基本语法是

btrfs scrub start /bvault

可以查询长时间擦洗的状态

btrfs scrub status /bvault

即使没有冗余数据,也应该执行此操作。

结论

上面揭示了 btrfs 功能和实现方面的许多“粗糙之处”,尤其是为 CentOS 启用它所采取的措施。尽管如此,这仍然比 ext2/3/4 和 XFS 好得多,因为它舍弃了所有理想的 btrfs 功能,因为错误是可以知道的,因为所有文件系统内容都经过校验和计算。

如果 btrfs 和 ZFS 的开发人员可以合作创建一个单一的内核模块,最大限度地共享“净室”代码,实现这两个文件系统,那将很有帮助。代码清除以前发生过,就在最近的记忆中;BSD 因清除 BSD “UNIX”实现中的 AT&T 源代码以生成 Net/2 而闻名。可以组织类似的努力来结束单个公司对文件系统源代码的控制。

Oracle 本身不愿意通过 GPL 或 BSD 许可证发布 ZFS 来解决这些问题。Oracle 还交付了一个功能不足、文档不适用且支持工具过时(用于 CentOS 8 转换)的 btrfs 实现。Oracle 是障碍,社区努力清除 ZFS 源代码中的 Oracle 贡献并将其与 btrfs 统一起来似乎是最直接的选择。

IBM 作为 Red Hat 的新所有者,处于独特的地位,能够部署文件系统工程师以净室方式复制所有必需的 Oracle 代码,并在实现 btrfs 和 ZFS 的 GPL 许可内核模块中实现。如果这样的文件系统可以替代地以 BSD 许可证发布,那么许多独立的操作系统可能会享受到高级文件系统功能(想象一下 z/OS 和 Haiku 之间的发送/接收)。

如果其他各方避免进行缺乏广泛 btrfs 功能和特性集的新文件系统尝试(即 Microsoft ReFS),那也将很有帮助。

在高级文件系统像 Linux 作为操作系统一样成为普遍商品的这一天到来之前,用户社区将继续在有问题的支持、缺乏功能和碎片化的 btrfs 社区中的解决方法之间左右为难。这是一个令人不安的境地,我们最好记住那些让我们身处此境地的各方。

Charles Fisher 拥有爱荷华大学的电气工程学位,并在一家财富 500 强矿业和制造公司担任系统和数据库管理员。

加载 Disqus 评论