当前位置:数码通 > 动态

btrfs:Linux中也终于有了一个可以和ZFS相媲美的文件系统

来源于 数码通 2023-10-05 16:29
undefined第一个是与可扩展性相关的功能。btrfs最重要的设计目标是应对大型机器对文件系统的可扩展性要求。 Extent、B-Tree和动态inode创建等特性保证了btrfs在大型机器上仍然表现良好,并且其整体性能不会随着系统容量的增加而下降。

其次,存在与数据完整性相关的特征。当系统面临不可预测的硬件故障时,Btrfs使用COW事务技术来保证文件系统的一致性。btrfs还支持校验和以避免静默腐败的发生。传统的文件系统无法做到这一点。

第三是与多设备管理相关的功能。 Btrfs 支持创建快照和克隆。btrfs还可以轻松管理多个物理设备,使传统的卷管理软件变得多余。

最后,还有其他难以分类的属性。这些功能都是比较先进的技术,可以显着提升文件系统的时间/空间性能,包括延迟分配、小文件存储优化、目录索引等。

可扩展性相关功能

B 树

btrfs文件系统中的所有metad数据均由BTree管理。使用 BTree 的主要好处是搜索、插入和删除操作都很高效。可以说BTree是btrfs的核心。

一味地吹嘘 BTree 非常好、高效可能没有说服力,但是如果你花一点时间看看 ext2/3 中元数据管理的实现,就可以凸显出 BTree 的优点。

阻碍 ext2/3 的可扩展性的一个问题来自于其目录的组织方式。目录是一种特殊的文件,其内容是ext2/3中的线性表。如图1-1[6]所示:

图 1. ext2 目录 [6]

FS Tree管理文件相关的元数据,如inode、dir等; Chunk Tree管理设备,每个磁盘设备在Chunk Tree中都有一个item;扩展树管理磁盘空间分配。btrfs每分配一块磁盘空间,就会将磁盘空间信息插入到Extent树中。查询Extent Tree会得到空闲磁盘空间信息;树根Tree保存了许多BTree的根节点。例如,用户每次创建快照时,btrfs都会创建一个FS Tree。为了管理所有的树,btrfs使用树根Tree来保存所有树的根节点; checksum Tree保存数据块的校验和。

基于范围的文件存储

许多现代文件系统使用范围而不是块来管理磁盘。范围是连续块的数量。范围由起始块加上长度来定义。

Extent可以有效减少元数据开销。为了进一步理解这个问题,我们来看一下ext2中的反面例子。

ext2/3以块为基本单位,将磁盘划分为多个块。为了管理磁盘空间,文件系统需要知道哪些块是空闲的。 Ext 使用位图来实现此目的。位图中的每一位对应于磁盘上的一个块。当分配相应的块时,位图中相应的位被设置为1。这是一个非常经典且清晰的设计,但不幸的是当磁盘容量增加时,位图本身占用的空间也会增加。这会导致可扩展性问题。随着存储设备容量的增大,位图元数据占用的空间也随之增大。人们希望无论磁盘容量如何增加,元数据都不要线性增加,这样的设计才能具有可扩展性。

下图比较了block和extent的区别:

图3. 使用范围的btrfs和使用位图的ext2/3

在ext2/3中,10个块需要10位来表示;在btrfs中,只需要一种元数据。对于大文件,extent 显示出更好的管理性能。

Extent是btrfs管理磁盘空间的最小单位,通过extent树来管理。 Btrfs 分配数据或元数据,需要查询范围树来获取可用空间信息。

动态索引节点分配

为了理解动态inode分配,你仍然需要使用ext2/3。下表列出了 ext2 文件系统的限制:

表 1. ext2 限制

图 4 显示了 ext2 的磁盘布局:

图 4. ext2 布局

在ext2中,inode区域是预先分配的并且具有固定的大小。例如,在100G的分区中,inode表区域只能存储131072个inode。这意味着不可能创建超过131072个文件,因为每个文件都必须有一个唯一的inode。

为了解决这个问题,必须动态分配inode。每个 inode 只是 BTree 中的一个节点。用户可以无限制地插入新的inode,其物理存储位置是动态分配的。所以,btrfs对于文件的数量是没有限制的。

优化支持 SSD

undefinedundefinedCOW事务可以保证文件系统的一致性,系统Reboot后无需执行fsck。因为超级块要么指向新的A'',要么指向A,以相同数据为准。

校验和

校验和技术确保数据可靠性并避免无声损坏。由于硬件原因,从磁盘读取的数据会不正确。例如A块存储的数据是0x55,但是读取到的数据变成了0x54。由于读操作不会报错,因此上层软件无法检测到这个错误。

解决这个问题的方法是保存数据的校验和,读取数据后检查校验和。如果不匹配,您就知道数据有问题。

ext2/3 没有校验和,并且完全信任磁盘。不幸的是,磁盘错误始终存在,不仅在廉价的 IDE 硬盘上,而且昂贵的 RAID 也存在静默损坏问题。而且随着存储网络的发展,即使从磁盘中正确读取数据,也很难保证能够安全地穿越网络设备。

btrfs在读取数据时读取其对应的校验和。如果最终从磁盘中读取的数据与校验和不同,则btrfs会首先尝试读取该数据的镜像备份。如果数据没有镜像备份,btrfs会返回错误。在将数据写入磁盘之前,btrfs 会计算数据的校验和。然后校验和和数据同时写入磁盘。

Btrfs使用单独的校验和树来管理数据块的校验和,将校验和与受校验和保护的数据块分开,从而提供更严格的保护。如果在每个数据块的头部添加一个字段来保存校验和,那么这个数据块就变成了一个保护自身的结构。在这种结构下存在无法检测到的错误。例如,文件系统原本要从磁盘读取块A,但返回了块B。由于校验和在块内部,因此校验和仍然是正确的。btrfs使用校验树来保存数据块的校验和,避免了上述问题。

Btrfs 使用 crc32 算法 来计算校验和,并且在未来的开发中将支持其他类型的校验算法。为了提高效率,btrfs使用不同的内核线程并行执行写入数据和校验和的工作。

与多设备管理相关的功能

每个 Unix 管理员都面临着为用户和各种应用程序分配磁盘空间的任务。大多数情况下,人们无法提前准确估计用户或应用程序将来需要多少磁盘空间。经常会发生磁盘空间耗尽的情况,必须尝试增加文件系统空间。传统的ext2/3无法满足这种需求。

许多卷管理软件都是为了满足用户多设备管理的需求而设计的,例如LVM。 Btrfs 集成了卷管理软件的功能,一方面简化了用户命令;另一方面提高了效率。

多设备管理

Btrfs 支持动态添加设备。用户在系统中添加新的磁盘后,可以使用btrfs命令将该设备添加到文件系统中。

为了灵活利用设备空间,Btrfs 将磁盘空间划分为多个 chunk。每个块可以使用不同的磁盘空间分配策略。例如,有些块仅存储元数据,有些块仅存储数据。一些块可以配置为镜像,而其他块可以配置为条带。这为用户提供了非常灵活的配置可能性。

音量

子体积是一个非常优雅的概念。即将文件系统的一部分配置为完整的子文件系统,称为子卷。

使用子卷,可以将一个大文件系统划分为多个子文件系统。这些子文件系统共享底层设备空间,并在需要磁盘空间时从底层设备分配,类似于应用程序调用 malloc() 分配内存。可以称为存储池。该模型具有充分利用磁盘带宽、简化磁盘空间管理等优点。

所谓充分利用磁盘带宽,是指文件系统可以并行读写多个底层磁盘。这是因为每个文件系统都可以访问所有磁盘。传统文件系统无法共享底层磁盘设备,无论是物理还是逻辑,因此无法实现并行读写。

undefinedundefined但是,btrfs使用BTree来管理目录项的方式并不能同时满足readdir的需求。 readdir 是 POSIX 标准 API,要求返回指定目录下的所有文件,特别是这些文件必须按 inode 编号排序。当btrfs目录项插入BTree时,Key不是Inode号,而是根据文件名计算出的哈希值。这种方法在搜索特定文件时非常高效,但不适合readdir。为此,btrfs每次创建新文件时,除了插入以哈希值作为Key的目录项外,还插入另一个目录项索引。目录项索引的KEY使用序列号作为BTree的键值。每次创建新文件时,该序列号都会线性增加。由于每次创建新文件时,索引节点号也会递增,因此序列号和索引节点号的顺序相同。使用这个序列号作为KEY在BTree中搜索,可以轻松得到按inode号排序的文件列表。

另外,按序号排序的文件在磁盘上往往是相邻的,因此按序号顺序访问大量文件会获得更好的IO效率。

压缩

大家都用过zip、winrar等压缩软件。压缩大文件可以有效节省磁盘空间。 Btrfs 具有内置压缩功能。

通常人们认为在将数据写入磁盘之前进行压缩会占用大量的CPU计算时间,这必然会降低文件系统的读写效率。然而,随着硬件技术的发展,CPU处理时间与磁盘IO时间的差距不断拉大。在某些情况下,需要消耗一定的CPU时间和一些内存,但是可以大大节省磁盘IO量,进而可以提高整体效率。

很多应用程序有预先分配磁盘空间的需要。他们可以通过 posix_fallocate 接口告诉文件系统在磁盘上预留一部分空间,但暂时并不写入数据。如果底层文件系统不支持 fallocate,那么应用程序只有使用 write 预先写一些无用信息以便为自己预留足够的磁盘空间。

由文件系统来支持预留空间更加有效,而且能够减少磁盘碎片,因为所有的空间都是一次分配,因而更有可能使用连续的空间。 Btrfs 支持 posix_fallocate 。

总结

至此,我们对 btrfs 的很多特性进行了较为详细的探讨,但 btrfs 能提供的特性却并不止这些。 btrfs 正处于试验开发阶段,还将有更多的特性。

Btrfs 也有一个重要的缺点,当 BTree 中某个节点出现错误时,文件系统将失去该节点之下的所有的文件信息。而 ext2/3 却避免了这种被称为”错误扩散”的问题。

但无论怎样,希望您和我一样,开始认同 btrfs 将是 Linux 未来最有希望的文件系统。

BTRFS 使用简介

了解了 btrfs 的特性,想必您一定想亲身体验一下 btrfs 的使用。本章将简要介绍如何使用 btrfs 。

创建文件系统

mkfs.btrfs 命令建立一个 btrfs 格式的文件系统。可以用如下命令在设备 sda5 上建立一个 btrfs 文件系统,并将其挂载到 /btrfsdisk 目录下:

这样一个 Btrfs 就在设备 sda5 上建立好了。值得一提的是在这种缺省情况下,即使只有一个设备,Btrfs 也会对 metadata 进行冗余保护。如果有多个设备,那么您可以在创建文件系统的时候进行 RAID 设置。详细信息请参见后续的介绍。

这里介绍其他几个 mkfs.btrfs 的参数。

Nodesize 和 leafsize 用来设定 btrfs 内部 BTree 节点的大小,缺省为一个 page 大小。但用户也可以使用更大的节点,以便增加 fanout,减小树的高度,当然这只适合非常大的文件系统。

Alloc-start 参数用来指定文件系统在磁盘设备上的起始地址。这使得用户可以方便的预留磁盘前面的一些特殊空间。

Byte-count 参数设定文件系统的大小,用户可以只使用设备的一部分空间,当空间不足时再增加文件系统大小。

修改文件系统的大小

当文件系统建立好之后,您可以修改文件系统的大小。 /dev/sda5 挂载到了 /btrfsdisk 下,大小为 800M 。假如您希望只使用其中的 500M,则需要减小当前文件系统的大小,这可以通过如下命令实现:

同样的,您可以使用 btrfsctl 命令增加文件系统的大小。

创建 Snapshot

下面的例子中,创建快照 snap1 时系统存在 2 个文件。创建快照之后,对 test1 的内容进行修改。再回到 snap1,打开 test1 文件,可以看到 test1 的内容依旧是之前的内容。

可以从上面的例子看到,快照 snap1 保存的内容不会被后续的写操作所改变。

创建 subvolume

使用 btrfs 命令,用户可以方便的建立 subvolume 。假设 /btrfsdisk 已经挂载到了 btrfs 文件系统,则用户可以在这个文件系统内创建新的 subvolume 。比如建立一个 /sub1 的 subvolume,并将 sub1 挂载到 /mnt/test 下:

Subvolme 可以方便管理员在文件系统上创建不同用途的子文件系统,并对其进行一些特殊的配置,比如有些目录下的文件关注节约磁盘空间,因此需要打开压缩,或者配置不同的 RAID 策略等。目前 btrfs 尚处于开发阶段,创建的 subvolme 和 snapshot 还无法删除。此外针对 subvolume 的磁盘 quota 功能也未能实现。但随着 btrfs 的不断成熟,这些功能必然将会进一步完善。

创建 RAID

mkfs 的时候,可以指定多个设备,并配置 RAID 。下面的命令演示了如何使用 mkfs.btrfs 配置 RAID1 。 Sda6 和 sda7 可以配置为 RAID1,即 mirror 。用户可以选择将数据配置为 RAID1,也可以选择将元数据配置为 RAID1 。

将数据配置为 RAID1,可以使用 mkfs.btrfs 的 -d 参数。如下所示:

添加新设备

当设备的空间快被使用完的时候,用户可以使用 btrfs-vol 命令为文件系统添加新的磁盘设备,从而增加存储空间。下面的命令向 /btrfsdisk 文件系统增加一个设备 /sda

-->
登录后参与评论