Btrfs 简史:

Btrfs 是 B 树文件系统,通常称为 Butter FS,或者是 B-tree FS 。关于它的历史我们要追溯到上世纪70年代,在1975年的时候,有一个非营利机构叫做 USENIX 成立了。

这个机构主要汇集了来自计算机操作系统的用户、开发者以及研究人员。他们的主要目的是学习和开发 Unix 以及类 Unix 的系统,在1977年的时候,因为 Unix 的商标被美国电话电报公司 AT&T 注册且拥有之后,这个组织的名称就改成了现在大家看到的这个样子。而在这个组织中,就有一位大家非常熟知的人物,北美最早的 Linux 内核开发人员,同时也是 ext2, ext3 和 ext4 文件系统开发者和维护者,曹子德先生,他也是 e2fsprogs 的开发者。

在2007年的时候, USENIX 中的一位成员,也是 IBM 的研究员,他的名字叫奥哈德·罗德,算是最早提出 Btrfs 核心数据结构思想的人了。同年,一位来自 SUSE ,开发 ReiserFS 的工程师,查尔斯梅森(Chris Mason),在年底的时候加入了甲骨文开始着手这个全新的项目,基于 B 树的文件系统——Btrfs。时间来到了2008年,这个时候的 ext4 文件系统开始增加一些特性,但是,是通过一些比较老的技术实现的,从某种角度来说,这仅仅是一种权宜之计,并不能实质性的改善。而相关的开发者们谈到 Btrfs 的时候,认为 Btrfs 才是更加直接的方法,因为 Btrfs 的灵活性、可靠性和管理方面的提升,是明显的,而且 Btrfs 在设计上借鉴了很多 reser3 和 4 的设计理念。于是在2008年底,Btrfs 文件系统的1.0版本发布了,并在2009年正式合并进入了 Linux 内核,与此同时,也有不少的 Linux 发行版开始实验性的使用 Btrfs 文件系统作为根目录文件系统,开始提供给用户使用。到了2011年7月,Linux内核主线版本来到3.0,那个时候的 Btrfs 文件系统正式将自动碎片整理和清理特性加入。而与此同时,甲骨文的梅森和在富士通的 MiaoXie 为 Btrfs 文件系统的性能提升做出了很多贡献。

我们把目光转向梅森,在2012年6月,梅森离开了甲骨文,加入了一个名字叫做 Fusion-IO 的公司,这个公司后来被 Sandisk 收购,这段时间的梅森仍然在为 Btrfs 文件系统不断做出贡献。这里,我们还要提另外一位 Btrfs 文件系统的开发者,他的名字叫做约瑟夫·巴奇克( Josef Bacik ),现在仍然是 Btrfs 文件系统的主要维护着和贡献者。

我们再回到 Btrfs 和 Linux 内核,在2012年,先后有两个 Linux 发行版将实验阶段 Btrfs 文件系统,转移到生产力环境 Linux 系统中,一个就是甲骨文的 Linux 系统,另一个就是 SUSE Linux 企业级系统,在2015年,SUSE Linux 企业级服务器正式将 Btrfs 文件系统作为默认的文件系统,与之相对的,在2017年,红帽宣布,红帽企业级 Linux 系统中不会计划迁移到 Btrfs 文件系统,到了2019年的红帽8企业级系统中,Btrfs 文件系统被完全移除了,然而在红帽旗下的社区发行版 Fedora 中,从33开始就选择 Btrfs 作为默认的文件系统了。

那么从整个 Btrfs 发展历程,从目前我所掌握的文档中,我们不难得到以下结论,Btrfs 的目的主要是为了取代 ext3 文件系统,改善单个文件的大小限制,总文件系统的大小,都加入 ext3 没有的功能,另外 Btrfs 在外人看来,更像是 ZFS 文件系统的复刻,都具有相类似的功能和特性,但是本质上和实现上是有区别的,所以各位朋友并不能简单理解 Btrfs 是 ZFS 的克隆。最后就是 Btrfs 在 Linux 树内文件系统中的核心竞争力:容错、修复还有易于管理。

Btrfs 目前还未支持,但将来计划加入的特性(截止 btrfs-progs v5.12.1):

  1. In-band data deduplication ,翻译过来,就是暂时还不支持写入时的去重;
  2. 联机文件系统检测,目前这个功能还并不能使用。或许有朋友会提到 btrfs scrub 命令实现,大家需要注意 btrfs scrub 这个命令和功能并不是文件系统检查器,它并不会检验,或者修复文件系统中的结构损坏,如果各位朋友一直以为它具有相关的功能,可能是因为 ZFS 的 zpool scrub 具有检测和修复的功能,那么,大家就以为 btrfs 同样具有了,然后,它仅仅是检查数据和树块的校验和,并不能确保树块的内容有效和一致。所以 btrfs scrub 并不能实现在线检测,还是需要用用 btrfs check 命令来实现,而实现的方法后续我们再聊;
  3. 目前6个硬盘设备以上,btrfs 对 raid5 和 raid6 还不支持。早期的 btrfs ,大概是3.19以后,存在write hole bug,后续在2017年8月1日的 RFC 补丁中得到修复。但还是存在一些问题,比方说不支持 trim ,也就是我们常说的修剪功能;算法能够尽可能支持多设备,但是 fixed-width 的条带卷就不受支持了。
  4. Object-level 的 raid0, raid1, raid10 目前还不支持,但是已经在计划中了。
  5. 加密功能正在筹备
  6. 读写缓存,一个类似 ZFS 的 ARC 和 L2ARC 的功能。关于 ZFS 的 ARC 和 L2ARC 我曾在之前的视频中提到过,通过这两个功能大大提升文件系统的读写速度,btrfs 文件系统已经在着手这方面的提升了

Btrfs 特性细谈:

在线磁盘碎片整理

常用命令:

btrfs filesystem defragment

命令中的选项大概的翻译,如有不准备请各位朋友指正:

-r                      #递归碎片整理
-c[zlib,lzo,zstd]       #碎片整理时压缩
-f                      #碎片整理完成后,立刻刷写到磁盘
-s                      #仅从字节开始进行碎片整理
-l                      #碎片整理时,最多len个字节
-t                      #提示目标大小范围,默认是32M
-v                      #全局 v 选项,但是已经弃用了`

Global options:
-v|--verbose            #这是增加输入时的信息

Warning: most Linux kernels will break up the ref-links of COW data
(e.g., files copied with 'cp --reflink', snapshots) which may cause
considerable increase of space usage. See btrfs-filesystem(8) for
more information.`

这里需要了解 cp --reflink 的含义,一般情况下,写时复制主要是文件发生了改变的时候才复制。所以为了解决快照,复制,写入对延迟敏感的进程的影响,在 Btrfs 中 cp --reflink 都是采用轻量化复制,即 cp --reflink=always

在线碎片整理,包括了手动方式和自动模式,自动模式需要在 /etc/fstab 这个文件中的 btrfs 这个挂载选项后面添加 autodefrag 就可以了。如果不需要,就是 noautodefrag 就可以了。

如何正确的理解在 Btrfs 文件系统中的磁盘碎片整理行为:

  • 优点:
    • 计算机在长期的工作中,文件反复读写操作形成了很多零碎的部分,在老式的磁盘中,磁头需要在飞轮中多次跳转才能完成一个大型文件的读写,但是完成了磁盘碎片整理后,文件将从零碎的状态回归到一个连续的状态,这样的目的就是能够更好完成读写操作。
  • 缺点:
    • 针对普通没有写时复制功能的文件系统,磁盘碎片整理的优点是很明显的,但是如果是在具有写时复制的文件系统上进行操作就不一定了。在进行磁盘碎片整理的时候,原始数据就会试图被扩展,把新数据加入进来并首位对其,看上去是一个非常整齐的操作,但是这个过程造成了新数据链接的副本丢失,文件系统需要增加时间重新去创建之前的副本链接,这个过程耗时,而且还需要扩展文件系统来完成这个过程;
    • 如果存在 Btrfs 文件系统子卷,并且对这些子卷做了很多快照,那么完成磁盘碎片整理之后,这些子卷与快照之间的链接也会被打断,后续 Btrfs 需要花费额外的时间和空间来重新构建之前的链接;
    • 如果 Btrfs 文件系统中存在大型的数据库或者是虚拟机磁盘镜像,那么碎片整理只能起到负面效果;
    • 此部分可以参考甲骨文官方文档

在线 Btrfs 扩容和收缩

经常使用到的命令:

btrfs filesystem resize max <已经挂载好 btrfs 的目录>
btrfs filesystem resize +/-<容量> <已经挂载好 btrfs 的目录>
btrfs filesystem usage <已经挂载好 btrfs 的目录>

扩容和收缩:

  • 需要了解的一些基础知识和信息:
    • 需要理解扇区,扇区是磁盘最小的读写单位;
    • 为什么扩容和收缩只能从尾部扇区开始,而不能从开头的扇区开始?解答:因为开头的部分不仅仅是启始扇区,启动扇区也是位于开头部分,在启始扇区保存了文件系统很多元数据,一旦移动了启始扇区,文件系统很多内容都要发生变化;
  • 具体操作步骤:
    • 首先是针对 btrfs 文件系统本身,需要使用到的命令:btrfs filesystem resize +/- <容量> <挂载点> ,通过这个命令来给 btrfs 实现缩小或者扩展;
    • 其次是对 btrfs 所在的分区进行操作,可以使用 cfdisk 或者 fdisk ,在使用后者 fdisk 的时候注意最后要保留 btrfs 的 sign ;
    • 最后在将 btrfs 文件系统调整大小符合分区大小。

所以具体理解 btrfs 扩容和收缩就类似于人体分离魔术中的人,而分区就是外部的框架

在线块设备添加和删除

经常使用到的命令:

btrfs device add /dev/sdX /
btrfs device remove /dev/sdX /
btrfs filesystem balance /
  • 需要了解和掌握的内容:
    • 可以直接在已经挂载到目录上的 btrfs 文件系统操作;
    • 这个过程中会将未格式化的硬盘设备先格式化成 btrfs 然后再添加进去,再平衡就可以;移除类似,直接移除,再平衡。

联机负载均衡

经常使用的命令:

btrfs filesystem balance

联机负载均衡有两重含义:

  • 第一层含义是操作部分,也就是平时我们使用命令行操作完成多个块设备的,比方说阵列之类的负载均衡的命令;
  • 第二层含义是概念部分,btrfs 文件系统在实现的 raid0,raid1,raid10,还有并不成熟的几个 raid 方案中的 block group 是垮设备的,从而实现了负载均衡。

简单介绍下 block group ,文件系统将磁盘空间划分为若干组,以这种组来管理磁盘磁盘空间。这个组就是块组,划分的意义从网上的资料中可以得知主要有两个方面:

1、上层访问数据是发生碰撞的概率大大降低,提升文件系统的整体性能;

2、方便对磁盘管理

离线文件系统检测

经常使用到的命令:

btrfs check --repair <device>
btrfs scrub start <挂载目录>
btrfs scrub status <挂载目录>

需要关注两个重要的问题:

  1. 修复的必要性
  2. 修复工具的可靠性

Note: Scrub is not a filesystem checker (fsck) and does not verify nor repair structural damage in the filesystem. It really only checks checksums of data and tree blocks, it doesn’t ensure the content of tree blocks is valid and consistent. There’s some validation performed when metadata blocks are read from disk but it’s not extensive and cannot substitute full btrfs check run.

以上引文大家可以通过 man btrfs-scrub 查看到,或者可以到这里看到。

需要修复的设备必须离线,或者换句话说就是在非挂载的情况下。另外从前 btrfs 有个工具,叫做 btrfsck ,已经被弃用。

文件系统级磁盘阵列

经常使用到的命令:

mkfs.btrfs -L data -d raidX -m raidX -n 4096 -f /dev/sdaX /dev/sdbX /dev/sdcX ... 

1. btrfs device scan
   mount /dev/<第一个设备> /<目录>

2. mount -o device=/dev/<设备1>,device=/dev/<设备2>,device=/dev/<设备3>... /dev/<设备1> /<目录>

3. 使用 fstab 完成开机自动挂载
   UUID=XXX    /<目录>  文件系统    挂载选项 0 0
   UUID=XXX    /<目录>  文件系统    device=/dev/<设备1>,...,挂载选项 0 0

详细了解 mkfs.btrfs 命令中提到的重要 options :

-b | --byte-count <size>

定义文件系统的大小,如果没有特殊需求或者没有定义这个值,将会使用完整的储存设备空间大小。

--csum <type>
--checksum <type>

定义使用什么算法来进行数据校验,默认提供的算法是 crc32c ,有效的算法值包括了 crc32c, xxhash, sha256, blake2 。需要内核支持相关算法。

P.S(个人观点是,使用默认的就可以,在 Linux 内核配置选项中,提供了默认开启 crc32c-intel 的支持,如果处理器正好是 intel ,那么校验就更加省时省力)

-d | --data <profile>

定义数据块组采用怎样的配置文件,有效的值包括:raid0, raid1, raid5, raid6, raid10, 单一或者冗余,那么冗余怎么理解,就是在同一个设备上储存文件存放两个,一个原始,一个副本,但是冗余不是备份。

-m | --metadata <profile>

定义元数据的块组,有效值和上面的是一样的,同样包含了 raid0, raid1, raid10, raid5, raid6 ,单一和冗余不过这里需要强调,如果是单个设备,默认启用冗余;但,如果检测到该单一设备是固态硬盘,默认启用的是单一(single)。它的检测方法是通过检测是否是固态硬盘还是机械硬盘实现的,具体通过:

/sys/block/DEV/queue/rotational
-M | --mixed

在默认情况下,数据块组和元数据块组是相互隔离的。如果使用了 mixed 模式,那么二者将会在同一个块组中储存。好处是更好的利用有效空间,适合小型储存设备。块组的单独分配,使得空间可以为其他块组类型保留,但是不可以用于分配并可能导致 ENOSPC 状态的情况。

官方推荐,如果储存设备空间小于1G,推荐使用 mixed 模式,如果你的文件系统小于5G的时候(小确推)使用 mixed。如果你在更大的文件系统中使用可能会降低性能,当然啦,也是可以用的,不至于不允许用或者不能用。即使是多个设备,比方说 raid 这种了情况。

在使用 mixed 模式的时候,我们一定要注意 nodesize 和 setorsize 必须相同,俗话说的4K对齐,并且块组类型也必须相符。

在4.2的版本 btrfs 是强制在1G的设备上使用 mixed 模式的,但是在4.3的版本之后,因为会出现一些使用便利性的问题,就移除了。

-n | --nodesize <size>

这里定义的是节点大小,换句话说就是 btrfs 文件系统储存元数据的树的块大小,默认值是16KiB(就是 16384字节)或者说是页面大小,当然,也可以调整的大一些。但是必须强调的是,这个值必须是 sectorsize 的倍数,同时也是是2的幂。

更小的 nodesize 会增加元数据块组的碎片,但是呢,可以增高 b-trees ,从而降低锁定争用。如果是更高的 nodesize ,在更新元数据块的时候,更高的节点大小以更“昂贵”的内存操作为代价提供更好的 b-trees 内 node 紧凑型和更少的碎片。

教科书中的 b-trees 中的 item 是等大的,但是 btrfs 中的 b-trees 大小是可变的,那就需要寻找一个变通的方法去接近教科书中最优的 b-trees ,从而增大 nodesize 可以相对而言在结果上更加接近那种最优的状态。

以上内容是FC老师的讲解

个人理解:如果你的内存小、频率低、使用固态硬盘,可以适当降低 nodesize ;如果你的内存容量大、频率高,可以适当增加 nodesize 。

大家请注意,在3.11及其以上版本的 btrfs 默认的 nodesize 是4K

-L | --label <string>

这里就是先前谈到的定义个标签,相当于给 btrfs 文件系统取一个名字。这段“名字”应该小于256个字节,并且不能有换行符,换句话说就是你不能再名字里用“回车”。

-K | --nodiscard

并不推荐在整个设备上使用,因为这个选项并不会影响到固态硬盘使用 btrfs 挂载中执行整理对齐操作,各位可以从挂载选项 discard 中获得启发。

-r | --rootdir <rootdir>

用来自 rootdir 的文件填充顶级子卷。这不需要 root 权限来写入新文件或挂载文件系统。

使用这个选项的目的用于扩大镜像或者文件,以确保足够大能够包含根目录下的文件。那么在 4.14.1 这个 btrfs 版本之前,是可以最小化文件系统大小的,但是这个版本之后就不行了。具体我们来看下面的 shrink 选项。

--shrink

收缩文件系统到最小的尺寸,这个选项只能工作在--rootdir 选项的时候;

如果目标只是一个标准的文件,那么该操作会通过截短该文件实现最小化尺寸。否则,该操作会减少文件系统可用空间,而不能扩容。除非将该文件系统挂载到目录下使用 btrfs filesystem resize 命令来扩容。

在 4.14.1 的 btrfs 及其以后的版本,收缩功能会自动完成。

-O | --features <feature1>[,<feature2>...]

一个可以列出并且在创建文件系统的时候就打开 btrfs 文件系统特性的选项。但是对于某些老内核,并不是所有的特性都能够支持,所以可以使用字符 ^ 作为前缀来禁用某些特性。

当想要查看所有的特性时,可以使用以下命令查看:

mkfs.btrfs -O list-all

第一部分学习总结:

涉及 btrfs 方面的内容,因为我个人也是一个学习的过程,所以分享给大家的并不一定正确,所有的内容还是要以官方文档为准。在最后,向各位开源社区做个小小的通知,在这个月,也就是6月19日,openSUSE社区将在重庆邮电大学举办一次线下活动,地址是重庆,川东第一道,观老君洞旁重庆邮电大学,邀请了来自北京的 SUSE 工程师做话题分享,同时也会有 Arch 和 Deepin 的开发者来现场和大家交流,欢迎大家来积极参加和报名,报名可以到 openSUSE 论坛相关帖子下留言或者到电报群和山木老哥说一下。

另外今天得知需要做登记,因为毕竟最近在疫情期间,另外要进入大学。

请及时完成,以方便来参加。

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注