本文将探讨 Btrfs 中的透明文件系统压缩及其如何帮助节省存储空间。 这是详细了解 Btrfs 系列的一部分,Btrfs 是 Fedora 工作站和 Fedora 银蓝自 Fedora Linux 33。
如果您错过了,请阅读本系列的上一篇文章:https://fedoramagazine.org/working-with-btrfs-snapshots
介绍
我们大多数人可能已经经历过存储空间不足的情况。 也许你想从网上下载一个大文件,或者你需要从手机中快速复制一些图片,操作突然失败。 虽然存储空间正在稳步变得更便宜,但越来越多的设备要么制造时具有固定的存储量,要么最终用户难以扩展。
但是,当存储空间不足时,您可以做什么? 也许您会求助于云存储,或者您会找到一些随身携带的外部存储方式。
在本文中,我将研究此问题的另一种解决方案:透明文件系统压缩,这是 Btrfs 中内置的一项功能。 理想情况下,这将解决您的存储问题,同时几乎不需要对您的系统进行任何修改! 让我们看看如何。
透明压缩解释
首先,让我们研究一下透明压缩的含义。 您可以使用 gzip、xz 或 bzip2 等压缩算法来压缩文件。 这通常是一个显式操作:您使用压缩实用程序并让它对您的文件进行操作。 虽然这提供了空间节省,但取决于文件内容,它有一个主要缺点:当您想要访问文件以读取或修改它时,您必须先解压缩它。
这不仅是一个繁琐的过程,而且还会暂时破坏您之前实现的空间节省。 此外,您最终会(解)压缩您最初不打算接触的文件部分。 显然还有比这更好的东西!
另一方面,透明压缩发生在文件系统级别。 在这里,压缩文件对用户来说仍然看起来像普通的未压缩文件。 但是,它们是在磁盘上应用压缩后存储的。 这是可行的,因为文件系统有选择地只解压缩您访问的文件部分,并确保在将更改写入磁盘时再次压缩它们。
这里的压缩是透明的,因为用户不会注意到它,除非在文件访问期间 CPU 负载可能会略有增加。 因此,您可以将其应用于现有系统,而无需进行硬件修改或诉诸云存储。
比较压缩算法
Btrfs 提供了多种压缩算法供您选择。 由于技术原因,它不能使用任意压缩程序。 目前支持:
- zstd
- 伊佐
- zlib
好消息是,由于透明压缩的工作方式,您不必为 Btrfs 安装这些程序即可使用它们。 在接下来的段落中,您将看到如何运行一个简单的基准测试来比较各个压缩算法。 但是,为了执行基准测试,您必须安装必要的可执行文件。 之后无需保留它们,因此您将使用 podman 容器来确保您不会在系统中留下任何痕迹。
笔记:由于 Btrfs 使用的压缩依赖于这些压缩算法的内核(重新)实现,因此应将这些算法的用户空间版本的结果视为粗略的近似值。
因为一遍又一遍地输入相同的命令是一项乏味的任务,所以我准备了一个可以运行的 bash 托管在 Gitlab 上的脚本(https://gitlab.com/hartang/btrfs-compression-test). 这将使用上述每种算法在不同的压缩级别运行单个压缩和解压缩。
首先,下载脚本:
$ curl -LO https://gitlab.com/hartang/btrfs-compression-test/-/raw/main/btrfs_compression_test.sh
接下来,旋转一个 Fedora 挂载当前工作目录的 Linux 容器,以便您可以与主机交换文件并在其中运行脚本:
$ podman run --rm -it --security-opt label=disable -v "$PWD:$PWD" -w "$PWD" registry.fedoraproject.org/fedora:37
最后运行脚本:
$ chmod +x ./btrfs_compression_test.sh $ ./btrfs_compression_test.sh
我机器上的输出如下所示:
[INFO] Using file 'glibc-2.36.tar' as compression target [INFO] Target file 'glibc-2.36.tar' not found, downloading now... ################################################################### 100.0% [ OK ] Download successful! [INFO] Copying 'glibc-2.36.tar' to '/tmp/tmp.vNBWYg1Vol/' for benchmark... [INFO] Installing required utilities [INFO] Testing compression for 'zlib' Level | Time (compress) | Compression Ratio | Time (decompress) -------+-----------------+-------------------+------------------- 1 | 0.322 s | 18.324 % | 0.659 s 2 | 0.342 s | 17.738 % | 0.635 s 3 | 0.473 s | 17.181 % | 0.647 s 4 | 0.505 s | 16.101 % | 0.607 s 5 | 0.640 s | 15.270 % | 0.590 s 6 | 0.958 s | 14.858 % | 0.577 s 7 | 1.198 s | 14.716 % | 0.561 s 8 | 2.577 s | 14.619 % | 0.571 s 9 | 3.114 s | 14.605 % | 0.570 s [INFO] Testing compression for 'zstd' Level | Time (compress) | Compression Ratio | Time (decompress) -------+-----------------+-------------------+------------------- 1 | 0.492 s | 14.831 % | 0.313 s 2 | 0.607 s | 14.008 % | 0.341 s 3 | 0.709 s | 13.195 % | 0.318 s 4 | 0.683 s | 13.108 % | 0.306 s 5 | 1.300 s | 11.825 % | 0.292 s 6 | 1.824 s | 11.298 % | 0.286 s 7 | 2.215 s | 11.052 % | 0.284 s 8 | 2.834 s | 10.619 % | 0.294 s 9 | 3.079 s | 10.408 % | 0.272 s 10 | 4.355 s | 10.254 % | 0.282 s 11 | 6.161 s | 10.167 % | 0.283 s 12 | 6.670 s | 10.165 % | 0.304 s 13 | 12.471 s | 10.183 % | 0.279 s 14 | 15.619 s | 10.075 % | 0.267 s 15 | 21.387 s | 9.989 % | 0.270 s [INFO] Testing compression for 'lzo' Level | Time (compress) | Compression Ratio | Time (decompress) -------+-----------------+-------------------+------------------- 1 | 0.447 s | 25.677 % | 0.438 s 2 | 0.448 s | 25.582 % | 0.438 s 3 | 0.444 s | 25.582 % | 0.441 s 4 | 0.444 s | 25.582 % | 0.444 s 5 | 0.445 s | 25.582 % | 0.453 s 6 | 0.438 s | 25.582 % | 0.444 s 7 | 8.990 s | 18.666 % | 0.410 s 8 | 34.233 s | 18.463 % | 0.405 s 9 | 41.328 s | 18.450 % | 0.426 s [INFO] Cleaning up... [ OK ] Benchmark complete!
在根据脚本中的数字做出决定之前,请务必注意以下几点:
- 并非所有文件的压缩效果都一样好。 现代多媒体格式(例如图像或电影)已经压缩了它们的内容,并且压缩得不够好。
- 该脚本只执行一次压缩和解压缩。 在同一个输入文件上重复运行它会产生略有不同的输出。 因此,时间应该被理解为估计值,而不是精确的测量值。
考虑到输出中的数字,我决定在我的系统上使用压缩级别为 3 的 zstd 压缩算法。 根据您的需要,您可能希望选择更高的压缩级别(例如 example,如果您的存储设备相对较慢)。 要估计可实现的读/写速度,您可以将源存档大小(约 260 MB)除以(解)压缩时间。
默认情况下,压缩测试适用于 GNU libc 2.36 源代码。 如果您想查看自定义文件的结果,您可以为脚本提供一个文件路径作为第一个参数。 请记住,该文件必须可以从容器内部访问。
如果您想测试其他一些东西或执行更详细的基准测试,请随意阅读脚本代码并根据自己的喜好修改它!
在 Btrfs 中配置压缩
Btrfs 中的透明文件系统压缩可以通过多种方式进行配置:
- 作为安装文件系统时的安装选项(适用于同一 Btrfs 文件系统的所有子卷)
- 使用 Btrfs 文件属性
- 在 btrfs 文件系统碎片整理期间(不是永久性的,此处未显示)
- 与chattr文件属性界面(此处未展示)
我只会看一下其中的前两个。
在挂载时启用压缩
有一个启用文件压缩的 Btrfs 挂载选项:
$ sudo mount -o compress=<ALGORITHM>:<LEVEL> ...
为了 example要挂载一个文件系统并在第 3 层使用 zstd 算法对其进行压缩,您可以这样写:
$ sudo mount -o compress=zstd:3 ...
设置压缩级别是可选的。 请务必注意,压缩挂载选项适用于整个 Btrfs 文件系统及其所有子卷。 此外,它是当前唯一受支持的指定要使用的压缩级别的方法。
为了对根文件系统应用压缩,必须在 /etc/fstab 中指定。 这 Fedora Linux 安装程序,用于 example,默认情况下在级别 1 上启用 zstd 压缩,在 /etc/fstab 中如下所示:
$ cat /etc/fstab [ ... ] UUID=47b03671-39f1-43a7-b0a7-db733bfb47ff / btrfs subvol=root,compress=zstd:1,[ ... ] 0 0
启用每个文件的压缩
指定压缩的另一种方法是通过 Btrfs 文件系统属性。 要读取任何文件、文件夹或子卷的压缩设置,请使用以下命令:
$ btrfs property get <PATH> compression
同样,您可以像这样配置压缩:
$ sudo btrfs property set <PATH> compression <VALUE>
为了 example为 /etc 下的所有文件启用 zlib 压缩:
$ sudo btrfs property set /etc compression zlib
您可以使用 man btrfs-property 获取支持值的列表。 请记住,此接口不允许指定压缩级别。 此外,如果设置了压缩属性,它会覆盖安装时配置的其他压缩。
压缩现有文件
此时,如果您对现有文件系统应用压缩并使用 df 或类似命令检查空间使用情况,您会发现没有任何变化。 这是因为 Btrfs 本身不会“重新压缩”所有现有文件。 只有在将新数据写入磁盘时才会进行压缩。 有几种方法可以执行显式重新压缩:
- 等待,什么都不做:当文件被修改并写回磁盘时,Btrfs 会按照配置压缩新写入的文件内容。 在某个时候,如果我们等待的时间足够长,我们的文件中就会有越来越多的部分被重写并因此被压缩。
- 将文件移动到不同的文件系统并再次移动回来:根据您要对其应用压缩的文件,这可能会成为一项相当繁琐的操作。
- 执行 Btrfs 碎片整理
最后一个选项可能是最方便的,但它对已经包含快照的 Btrfs 文件系统有一个警告:它会破坏快照之间的共享范围。 换句话说,两个快照之间的所有共享内容,或一个快照及其父子卷,将在碎片整理操作后多次出现。
因此,如果您的文件系统上已经有很多快照,则不应在整个文件系统上运行碎片整理。 这也不是必需的,因为使用 Btrfs,您可以对特定目录甚至单个文件进行碎片整理,如果您愿意的话。
您可以使用以下命令执行碎片整理:
$ sudo btrfs filesystem defragment -r /path/to/defragment
为了 example,您可以像这样对您的主目录进行碎片整理:
$ sudo btrfs filesystem defragment -r "$HOME"
如有疑问,最好先对单个大文件进行碎片整理,然后继续处理越来越大的目录,同时监视文件系统上的可用空间。
测量文件系统压缩
在某些时候,您可能想知道由于文件系统压缩,您节省了多少空间。 但是你怎么知道呢? 首先,要判断 Btrfs 文件系统是否已安装并应用了压缩,您可以使用以下命令:
$ findmnt -vno OPTIONS /path/to/mountpoint | grep compress
如果得到结果,则给定挂载点的文件系统正在使用压缩! 接下来,compsize 命令可以告诉您文件需要多少空间:
$ sudo compsize -x /path/to/examine
在我的主目录中,结果如下所示:
$ sudo compsize -x "$HOME" Processed 942853 files, 550658 regular extents (799985 refs), 462779 inline. Type Perc Disk Usage Uncompressed Referenced TOTAL 81% 74G 91G 111G none 100% 67G 67G 77G zstd 28% 6.6G 23G 33G
各行告诉您应用于文件的压缩“类型”。 “TOTAL”是它下面所有行的总和。 另一方面,这些列告诉您我们的文件需要多少空间:
- “Disk Usage”是硬盘驱动器上分配的实际存储量,
- “未压缩”是文件在不应用压缩的情况下需要的存储量,
- “引用”是所有未压缩文件加起来的总大小。
“引用”可能与“未压缩”中的数字不同,如果,对于 example,一个以前有重复数据删除的文件,或者是否有共享范围的快照。 在里面 example 在上面,您可以看到 91 GB 的未压缩文件仅占用我磁盘上 74 GB 的存储空间! 根据存储在目录中的文件类型和应用的压缩级别,这些数字可能会有很大差异。
关于文件压缩的附加说明
Btrfs 使用启发式算法检测压缩文件。 这样做是因为压缩文件通常不能很好地压缩,因此没有必要浪费 CPU 周期来尝试进一步压缩。 为此,Btrfs 在将数据写入磁盘之前压缩数据时会测量压缩率。 如果文件的第一部分压缩得不好,该文件将被标记为不可压缩,并且不会进行进一步的压缩。
如果出于某种原因,您希望 Btrfs 压缩它写入的所有数据,您可以使用 compress-force 选项挂载 Btrfs 文件系统,如下所示:
$ sudo mount -o compress-force=zstd:3 ...
像这样配置时,Btrfs 将使用压缩级别 3 的 zstd 算法压缩它写入磁盘的所有数据。
需要注意的重要一点是,与未应用压缩的情况相比,启用大量数据和压缩的 Btrfs 文件系统的挂载时间可能要长几秒钟。 这有技术原因,是不影响文件系统操作的正常行为。
结论
本文详细介绍了 Btrfs 中的透明文件系统压缩。 它是一种内置的、相对便宜的方法,无需修改即可从现有硬件中获取一些额外的存储空间。
本系列的下一篇文章将涉及:
- Qgroups——限制你的文件系统大小
- RAID – 替换您的 mdadm 配置
如果您想了解更多与 Btrfs 相关的其他主题,请查看 Btrfs Wiki [1] 和文档 [2]. 如果您还没有阅读本系列的前三篇文章,请不要忘记阅读! 如果您觉得本系列文章中缺少某些内容,请在下面的评论中告诉我。 下篇文章见!
来源
[1]: https://btrfs.wiki.kernel.org/index.php/Main_Page
[2]: https://btrfs.readthedocs.io/en/latest/Introduction.html