消除重复的Warp -speed高级只读文件系统。
适用于 Linux 和 Windows 的快速高压缩只读文件系统。
DwarFS 是一个只读文件系统,专注于实现非常高的压缩比,特别是对于非常冗余的数据。
这听起来可能不太令人兴奋,因为如果它是多余的,它应该可以很好地压缩。然而,我发现其他只读、压缩文件系统在利用这种冗余方面做得不太好。请参阅此处与其他压缩文件系统的比较。
DwarFS 也不会在速度上妥协,对于我的用例,我发现它与 SquashFS 相当或性能更好。对于我的主要用例, DwarFS 压缩比 SquashFS 压缩好一个数量级,构建文件系统的速度快 6 倍,访问 DwarFS 上的文件通常更快,并且使用更少的 CPU 资源。
为了让您了解 DwarFS 的功能,以下是 DwarFS 和 SquashFS 在一组总大小为 39 GiB 的视频文件上的快速比较。不同之处在于,每个唯一的视频文件都有两个具有不同音频流集的同级文件(这是一个实际用例)。因此,视频和音频数据都存在冗余,但由于流是交错的,并且相同的块通常相距很远,因此利用该冗余进行压缩具有挑战性。 SquashFS 本质上根本无法压缩源数据,而 DwarFS 能够将大小减少近 3 倍,接近理论最大值:
$ du -hs dwarfs-video-test
39G dwarfs-video-test
$ ls -lh dwarfs-video-test.*fs
-rw-r--r-- 1 mhx users 14G Jul 2 13:01 dwarfs-video-test.dwarfs
-rw-r--r-- 1 mhx users 39G Jul 12 09:41 dwarfs-video-test.squashfs
此外,当安装 SquashFS 映像并使用 fio-3.34 执行随机读取吞吐量测试时, squashfuse
和squashfuse_ll
最高速度约为 230 MiB/s:
$ fio --readonly --rw=randread --name=randread --bs=64k --direct=1
--opendir=mnt --numjobs=4 --ioengine=libaio --iodepth=32
--group_reporting --runtime=60 --time_based
[...]
READ: bw=230MiB/s (241MB/s), 230MiB/s-230MiB/s (241MB/s-241MB/s), io=13.5GiB (14.5GB), run=60004-60004msec
相比之下,DwarFS 能够维持20 GiB/s 的随机读取速率:
READ: bw=20.2GiB/s (21.7GB/s), 20.2GiB/s-20.2GiB/s (21.7GB/s-21.7GB/s), io=1212GiB (1301GB), run=60001-60001msec
DwarFS 的显着特点是:
使用相似性哈希函数按相似性对文件进行聚类。这使得更容易利用跨文件边界的冗余。
跨文件系统块的分段分析,以减少未压缩文件系统的大小。这在使用压缩文件系统时可以节省内存,因此可能会允许更高的缓存命中率,因为缓存中可以保存更多数据。
分类框架对文件甚至文件片段进行分类,然后以不同的方式处理各个类别。例如,这使您不必浪费时间尝试压缩不可压缩的文件或使用 FLAC 压缩来压缩 PCM 音频数据。
高度多线程实现。文件系统创建工具和 FUSE 驱动程序都能够充分利用系统的多个核心。
我从 2013 年开始研究 DwarFS,我的主要用例和主要动机是我有数百个不同版本的 Perl,它们占用了大约 30 GB 的磁盘空间,而且我不愿意花费超过 10% 的硬盘空间。开车时把它们放在身边,以备不时之需。
在那之前,我一直在使用 Cromfs 将它们压缩成可管理的大小。然而,我对构建文件系统映像所花费的时间越来越恼火,更糟糕的是,它通常会在大约一个小时左右后崩溃。
我显然也研究过 SquashFS,但从来没有接近过 Cromfs 的压缩率。
仅此一点还不足以让我开始编写 DwarFS,但大约在同一时间,我非常着迷于较新的 C++ 标准的最新发展和功能,并且真的想要一个 C++ 业余爱好项目。另外,我想用 FUSE 做一些事情已经有一段时间了。最后但并非最不重要的一点是,我一直在思考压缩文件系统的问题,并且有一些我绝对想尝试的想法。
大部分代码是在 2013 年编写的,然后我每隔一段时间就会进行一些清理、错误修复和重构,但我从未真正达到让我乐意发布它的状态。由于它依赖于 Facebook 的(非常棒的)愚蠢的库,所以构建起来太尴尬了,而且它没有任何文档。
今年再次挖掘该项目,情况看起来并不像以前那么严峻。 Folly 现在使用 CMake 构建,因此我只是将其作为子模块拉入。大多数其他依赖项可以通过应该广泛可用的包来满足。我也写了一些基本文档。
DwarFS 通常应该可以通过开箱即用的最小更改构建良好。如果没有,请提出问题。我已经使用 Ubuntu(22.04 和 24.04)、Fedora Rawhide 和 Arch 的 Docker 映像设置了 CI 作业,它们可以帮助确定一组最新的依赖项。请注意,从发布 tarball 构建需要的依赖项比从 git 存储库构建要少,特别是从发布 tarball 构建时不需要ronn
工具以及 Python 和mistletoe
Python 模块。
有一些事情需要注意:
人们倾向于尝试将 folly 和 fbthrift 库拆分为子模块并与 DwarFS 一起构建。虽然我同意这种观点,但不幸的是这是一个坏主意。除了 folly 没有对 ABI 稳定性做出任何声明(即,您不能仅将针对一个版本的 folly 构建的二进制文件动态链接到另一个版本)之外,甚至不可能安全地链接到使用不同编译构建的 folly 库选项。即使是细微的差异(例如 C++ 标准版本)也可能导致运行时错误。详情请参阅本期。目前,甚至不可能使用 folly/fbthrift 的外部版本,因为 DwarFS 正在构建这两个库的最小子集;这些都捆绑在dwarfs_common
库中,并且严格在内部使用,即针对 DwarFS 库构建时不需要任何愚蠢或 fbthrift 标头。
使用系统安装的 GoogleTest 版本时可能会出现类似的问题。 GoogleTest 本身建议将其作为构建的一部分进行下载。但是,您可以通过将-DPREFER_SYSTEM_GTEST=ON
传递给cmake
调用来使用系统安装的版本。使用风险自负。
对于其他捆绑库(即fmt
、 parallel-hashmap
、 range-v3
),只要满足最低版本要求,就使用系统安装的版本。否则,将在构建期间获取首选版本。
每个版本都有适用于Linux-x86_64
、 Linux-aarch64
和Windows-AMD64
的预构建静态链接二进制文件可供下载。这些应该在没有任何依赖关系的情况下运行,并且在您无法轻松地从源代码构建工具的旧发行版上尤其有用。
除了二进制 tarball 之外,还有适用于每种架构的通用二进制文件。这些通用二进制文件在单个可执行文件中包含所有工具( mkdwarfs
、 dwarfsck
、 dwarfsextract
和dwarfs
FUSE 驱动程序)。这些可执行文件是使用 upx 压缩的,因此它们比单个工具的总和要小得多。然而,这也意味着每次运行二进制文件时都需要解压缩,这可能会产生很大的开销。如果这是一个问题,您可以坚持使用“经典”单个二进制文件,也可以解压缩通用二进制文件,例如:
upx -d dwarfs-universal-0.7.0-Linux-aarch64
通用二进制文件可以通过以适当工具命名的符号链接运行。例如:
$ ln -s dwarfs-universal-0.7.0-Linux-aarch64 mkdwarfs
$ ./mkdwarfs --help
如果文件系统支持符号链接,这也适用于 Windows:
> mklink mkdwarfs.exe dwarfs-universal-0.7.0-Windows-AMD64.exe
> .mkdwarfs.exe --help
或者,您可以通过传递--tool=<name>
作为命令行上的第一个参数来选择该工具:
> .dwarfs-universal-0.7.0-Windows-AMD64.exe --tool=mkdwarfs --help
请注意,就像dwarfs.exe
Windows 二进制文件一样,通用 Windows 二进制文件依赖于 WinFsp 项目中的winfsp-x64.dll
。但是,对于通用二进制文件,DLL 是延迟加载的,因此您仍然可以在没有 DLL 的情况下使用所有其他工具。有关更多详细信息,请参阅 Windows 支持部分。
DwarFS 使用 CMake 作为构建工具。
它同时使用 Boost 和 Folly,尽管后者作为子模块包含在内,因为很少有发行版实际上为其提供软件包。 Folly 本身有许多依赖项,因此请在此处查看最新列表。
它还使用 Facebook Thrift,特别是frozen
库,以高度空间效率、内存可映射和定义明确的格式存储元数据。它也作为子模块包含在内,我们只构建编译器和一个非常精简的库,其中包含足以让 DwarFS 工作的库。
除此之外,DwarFS 实际上只依赖于 FUSE3 和 Folly 已经依赖的一组压缩库(即 lz4、zstd 和 liblzma)。
如果您使用测试进行构建,对 googletest 的依赖将自动解决。
基于 apt 的系统的一个好的起点可能是:
$ apt install
gcc
g++
clang
git
ccache
ninja-build
cmake
make
bison
flex
fuse3
pkg-config
binutils-dev
libacl1-dev
libarchive-dev
libbenchmark-dev
libboost-chrono-dev
libboost-context-dev
libboost-filesystem-dev
libboost-iostreams-dev
libboost-program-options-dev
libboost-regex-dev
libboost-system-dev
libboost-thread-dev
libbrotli-dev
libevent-dev
libhowardhinnant-date-dev
libjemalloc-dev
libdouble-conversion-dev
libiberty-dev
liblz4-dev
liblzma-dev
libzstd-dev
libxxhash-dev
libmagic-dev
libparallel-hashmap-dev
librange-v3-dev
libssl-dev
libunwind-dev
libdwarf-dev
libelf-dev
libfmt-dev
libfuse3-dev
libgoogle-glog-dev
libutfcpp-dev
libflac++-dev
nlohmann-json3-dev
请注意,使用gcc
构建时,优化级别将设置为-O2
而不是发布版本的 CMake 默认值-O3
。至少对于gcc-10
之前的版本, -O3
构建比使用-O2
的构建慢 70% 。
首先,解压发布存档:
$ tar xvf dwarfs-x.y.z.tar.xz
$ cd dwarfs-x.y.z
或者,您也可以克隆 git 存储库,但请注意,这具有更多依赖性,并且构建可能需要更长的时间,因为发布存档附带了从存储库构建时必须生成的大多数自动生成的文件:
$ git clone --recurse-submodules https://github.com/mhx/dwarfs
$ cd dwarfs
安装所有依赖项后,您可以使用以下命令构建 DwarFS:
$ mkdir build
$ cd build
$ cmake .. -GNinja -DWITH_TESTS=ON
$ ninja
然后您可以使用以下命令运行测试:
$ ctest -j
默认情况下,所有二进制文件都使用 jemalloc 作为内存分配器,因为与glibc
或tcmalloc
分配器相比,它通常使用更少的系统内存。要禁用jemalloc
的使用,请在cmake
命令行上传递-DUSE_JEMALLOC=0
。
还可以独立构建/安装 DwarFS 库、工具和 FUSE 驱动程序。这在打包 DwarFS 时最有趣。请注意,工具和 FUSE 驱动程序要求已构建或已安装库。要仅构建库,请使用:
$ cmake .. -GNinja -DWITH_TESTS=ON -DWITH_LIBDWARFS=ON -DWITH_TOOLS=OFF -DWITH_FUSE_DRIVER=OFF
测试并安装库后,您可以使用以下命令构建工具(即mkdwarfs
、 dwarfsck
、 dwarfsextract
):
$ cmake .. -GNinja -DWITH_TESTS=ON -DWITH_LIBDWARFS=OFF -DWITH_TOOLS=ON -DWITH_FUSE_DRIVER=OFF
要构建 FUSE 驱动程序,请使用:
$ cmake .. -GNinja -DWITH_TESTS=ON -DWITH_LIBDWARFS=OFF -DWITH_TOOLS=OFF -DWITH_FUSE_DRIVER=ON
安装非常简单:
$ sudo ninja install
尽管您不必安装工具来使用它们。
强烈建议不要尝试构建静态链接的二进制文件,并且不受官方支持。话虽这么说,以下是如何设置一个可以构建静态二进制文件的环境。
这已使用ubuntu-22.04-live-server-amd64.iso
进行了测试。首先,安装上面列出的所有依赖项。还安装:
$ apt install ccache ninja libacl1-dev
ccache
和ninja
是可选的,但有助于快速编译。
根据您的发行版,您需要构建和安装某些库的静态版本,例如 Ubuntu 的libarchive
和libmagic
:
$ wget https://github.com/libarchive/libarchive/releases/download/v3.6.2/libarchive-3.6.2.tar.xz
$ tar xf libarchive-3.6.2.tar.xz && cd libarchive-3.6.2
$ ./configure --prefix=/opt/static-libs --without-iconv --without-xml2 --without-expat
$ make && sudo make install
$ wget ftp://ftp.astron.com/pub/file/file-5.44.tar.gz
$ tar xf file-5.44.tar.gz && cd file-5.44
$ ./configure --prefix=/opt/static-libs --enable-static=yes --enable-shared=no
$ make && make install
就是这样!现在您可以尝试为 DwarFS 构建静态二进制文件:
$ git clone --recurse-submodules https://github.com/mhx/dwarfs
$ cd dwarfs && mkdir build && cd build
$ cmake .. -GNinja -DWITH_TESTS=ON -DSTATIC_BUILD_DO_NOT_USE=ON
-DSTATIC_BUILD_EXTRA_PREFIX=/opt/static-libs
$ ninja
$ ninja test
请查看 mkdwarfs、dwarfs、dwarfsck 和 dwarfsextract 的手册页。您还可以使用每个二进制文件的--man
选项访问手册页,例如:
$ mkdwarfs --man
dwarfs 手册页还显示了使用 overlayfs 设置 DwarFS 的示例,以便在只读 DwarFS 映像之上创建可写文件系统挂载。
DwarFS 文件系统格式的描述可以在 dwarfs-format 中找到。
此序列图中显示了mkdwarfs
内部操作的高级概述。
如果您使用 CMake 构建项目,那么使用 DwarFS 库应该非常简单。为了快速入门,请查看示例代码,该代码使用库来打印有关 DwarFS 图像的信息(如dwarfsck
)或提取它(如dwarfsextract
)。
有五个单独的库:
dwarfs_common
包含所有其他库所需的通用代码。接口在dwarfs/
中定义。
dwarfs_reader
包含从 DwarFS 映像读取数据所需的所有代码。接口在dwarfs/reader/
中定义。
dwarfs_extractor
包含使用libarchive
提取 DwarFS 映像所需的代码。这些接口在dwarfs/utility/filesystem_extractor.h
中定义。
dwarfs_writer
包含创建 DwarFS 图像所需的代码。接口在dwarfs/writer/
中定义。
dwarfs_rewrite
包含重写 DwarFS 图像的代码。这些接口在dwarfs/utility/rewrite_filesystem.h
中定义。
internal
子文件夹中的标头只能在构建时访问,并且不会安装。 tool
子文件夹也是如此。
读取器和提取器 API 应该相当稳定。编写器 API 可能会发生变化。但请注意,在该项目达到版本 1.0.0 之前,无法保证 API 稳定性。
对 Windows 操作系统的支持目前处于实验阶段。在过去的二十年里,我几乎完全在 Unix 世界中工作,因此我在 Windows 开发方面的经验相当有限,并且我预计 Windows 代码中肯定存在错误和粗糙的边缘。
Windows 版本的 DwarFS 文件系统驱动程序依赖于出色的 WinFsp 项目,并且其winfsp-x64.dll
必须可由dwarfs.exe
驱动程序发现。
无论您是在 Linux 还是 Windows 上使用不同的工具,它们的行为都应该几乎相同。文件系统映像可以在 Linux 和 Windows 之间复制,并且在一个操作系统上创建的映像应该可以在另一个操作系统上正常工作。
不过,有几点值得指出:
DwarFS 在 Windows 上支持硬链接和符号链接,就像在 Linux 上一样。然而,创建硬链接和符号链接似乎需要 Windows 上的管理员权限,因此,如果您想要提取包含某种链接的 DwarFS 映像,如果您没有正确的权限,则可能会遇到错误。
由于 WinFsp 中的问题,符号链接当前无法指向已安装的文件系统之外。此外,由于 WinFsp 中的另一个问题,带有驱动器号的符号链接将出现错误的目标路径。
Windows 上的 DwarFS 驱动程序通过其 API 正确报告硬链接计数,但目前这些计数未正确传播到 Windows 文件系统层。这可能是由于 WinFsp 中的问题造成的。
在 Windows 上挂载 DwarFS 映像时,挂载点不能存在。这与 Linux 不同,Linux 中挂载点必须实际存在。此外,还可以将 DwarFS 映像挂载为驱动器号,例如
dwarfs.exe image.dwarfs Z:
mkdwarfs
的过滤规则始终需要 Unix 路径分隔符,无论它是在 Windows 还是 Linux 上运行。
由于 vcpkg,在 Windows 上构建并不太复杂。您需要安装:
Visual Studio 和 MSVC C/C++ 编译器
git
CMake
忍者
操作系统
WinFsp
预计安装在C:Program Files (x86)WinFsp
;如果不是,则需要在通过cmake/win.bat
运行 CMake 时设置WINFSP_PATH
。
现在您需要克隆vcpkg
和dwarfs
:
> cd %HOMEPATH%
> mkdir git
> cd git
> git clone https://github.com/Microsoft/vcpkg.git
> git clone https://github.com/mhx/dwarfs
然后,引导vcpkg
:
> .vcpkgbootstrap-vcpkg.bat
并构建 DwarFS:
> cd dwarfs
> mkdir build
> cd build
> ..cmakewin.bat
> ninja
完成后,您应该能够运行测试。根据您机器中CPU核心的数量设置CTEST_PARALLEL_LEVEL
。
> set CTEST_PARALLEL_LEVEL=10
> ninja test
DwarFS 库和工具( mkdwarfs
、 dwarfsck
、 dwarfsextract
)现在可从 Homebrew 获取:
$ brew install dwarfs
$ brew test dwarfs
macOS 版本的 DwarFS 文件系统驱动程序依赖于很棒的 macFUSE 项目。在添加公式之前,您必须手动构建 DwarFS FUSE 驱动程序。
在 macOS 上构建应该相对简单:
安装自制软件
使用 Homebrew 安装必要的依赖项:
$ brew install cmake ninja macfuse brotli howard-hinnant-date double-conversion
fmt glog libarchive libevent flac openssl nlohmann-json pkg-config
range-v3 utf8cpp xxhash boost zstd
首次安装 macFUSE 时,您需要在系统偏好设置/隐私和安全中明确允许该软件。此后您很可能必须重新启动。
从发布页面下载发布 tarball 并解压:
$ wget https://github.com/mhx/dwarfs/releases/download/v0.10.0/dwarfs-0.10.0.tar.xz
$ tar xf dwarfs-0.10.0.tar.xz
$ cmake --fresh -B dwarfs-build -S dwarfs-0.10.0 -GNinja -DWITH_TESTS=ON
$ cmake --build dwarfs-build
$ ctest --test-dir dwarfs-build -j
brew install
中省略macfuse
,并使用以下命令代替上面的第一个cmake
命令: $ cmake --fresh -B dwarfs-build -S dwarfs-0.10.0 -GNinja -DWITH_TESTS=ON -DWITH_FUSE_DRIVER=OFF
$ cmake --fresh -B dwarfs-build -S dwarfs-0.10.0 -GNinja -DWITH_TESTS=ON -DWITH_LIBDWARFS=OFF -DWITH_TOOLS=OFF
$ sudo cmake --install dwarfs-build
就是这样!
天文摄影可以生成大量原始图像数据。在一个晚上,最终可能会产生几十 GB 的数据。对于大多数专用天文摄影相机,这些数据最终都会以 FITS 图像的形式出现。这些格式通常是未压缩的,使用标准压缩算法不能很好地压缩,并且虽然存在某些压缩的 FITS 格式,但它们并未得到广泛支持。
其中一种压缩格式(简称为“Rice”)压缩效果相当好,而且速度非常快。然而,其压缩 FITS 的实现有一些缺点。最严重的缺点是,对于颜色传感器和分辨率低于 16 位的传感器,压缩效果并不理想。
DwarFS 支持ricepp
(Rice++) 压缩,该压缩基于 Rice 压缩的基本思想,但进行了一些增强:它可以更好地压缩彩色和低位深度图像,并且在压缩过程中始终搜索最佳解决方案,而不是依赖启发式算法。
让我们看一个使用 ASI1600MM 相机拍摄的 129 张图像(黑暗、平坦和明亮)的示例。每个图像为 32 MiB,因此总共 4 GiB 的数据。使用标准fpack
工具压缩这些文件大约需要 16.6 秒,总输出大小为 2.2 GiB:
$ time fpack */*.fit */*/*.fit
user 14.992
system 1.592
total 16.616
$ find . -name '*.fz' -print0 | xargs -0 cat | wc -c
2369943360
但是,这会给您留下并非每个应用程序都能真正读取的*.fz
文件。
使用 DwarFS,我们得到以下结果:
$ mkdwarfs -i ASI1600 -o asi1600-20.dwarfs -S 20 --categorize
I 08:47:47.459077 scanning "ASI1600"
I 08:47:47.491492 assigning directory and link inodes...
I 08:47:47.491560 waiting for background scanners...
I 08:47:47.675241 scanning CPU time: 1.051s
I 08:47:47.675271 finalizing file inodes...
I 08:47:47.675330 saved 0 B / 3.941 GiB in 0/258 duplicate files
I 08:47:47.675360 assigning device inodes...
I 08:47:47.675371 assigning pipe/socket inodes...
I 08:47:47.675381 building metadata...
I 08:47:47.675393 building blocks...
I 08:47:47.675398 saving names and symlinks...
I 08:47:47.675514 updating name and link indices...
I 08:47:47.675796 waiting for segmenting/blockifying to finish...
I 08:47:50.274285 total ordering CPU time: 616.3us
I 08:47:50.274329 total segmenting CPU time: 1.132s
I 08:47:50.279476 saving chunks...
I 08:47:50.279622 saving directories...
I 08:47:50.279674 saving shared files table...
I 08:47:50.280745 saving names table... [1.047ms]
I 08:47:50.280768 saving symlinks table... [743ns]
I 08:47:50.282031 waiting for compression to finish...
I 08:47:50.823924 compressed 3.941 GiB to 1.201 GiB (ratio=0.304825)
I 08:47:50.824280 compression CPU time: 17.92s
I 08:47:50.824316 filesystem created without errors [3.366s]
⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯
waiting for block compression to finish
5 dirs, 0/0 soft/hard links, 258/258 files, 0 other
original size: 3.941 GiB, hashed: 315.4 KiB (18 files, 0 B/s)
scanned: 3.941 GiB (258 files, 117.1 GiB/s), categorizing: 0 B/s
saved by deduplication: 0 B (0 files), saved by segmenting: 0 B
filesystem: 3.941 GiB in 4037 blocks (4550 chunks, 516/516 fragments, 258 inodes)
compressed filesystem: 4037 blocks/1.201 GiB written
在不到 3.4 秒的时间内,它将数据压缩至 1.2 GiB,几乎是fpack
输出大小的一半。
除了节省大量磁盘空间之外,当您的数据存储在 NAS 上时,这也很有用。以下是通过 1 Gb/s 网络连接访问的同一组数据的比较,首先使用未压缩的原始数据:
find /mnt/ASI1600 -name '*.fit' -print0 | xargs -0 -P4 -n1 cat | dd of=/dev/null status=progress
4229012160 bytes (4.2 GB, 3.9 GiB) copied, 36.0455 s, 117 MB/s
接下来在同一共享上使用 DwarFS 映像:
$ dwarfs /mnt/asi1600-20.dwarfs mnt
$ find mnt -name '*.fit' -print0 | xargs -0 -P4 -n1 cat | dd of=/dev/null status=progress
4229012160 bytes (4.2 GB, 3.9 GiB) copied, 14.3681 s, 294 MB/s
这大约快了 2.5 倍。对于速度较慢的外部硬盘,您很可能会看到类似的结果。
目前,DwarFS 没有内置功能将恢复信息添加到文件系统映像。但是,出于存档目的,最好拥有此类恢复信息,以便能够修复损坏的图像。
幸运的是,使用 par2cmdline 之类的东西相对简单:
$ par2create -n1 asi1600-20.dwarfs
这将创建两个额外的文件,您可以将它们放置在映像旁边(或放置在不同的存储上),因为只有当 DwarFS 检测到文件系统映像存在问题时,您才需要它们。如果出现问题,您可以运行
$ par2repair asi1600-20.dwarfs
如果少于 5%(这是par2create
使用的默认值)的图像损坏,它很可能能够恢复图像。
目前不支持扩展属性。使用mkdwarfs
构建 DwarFS 映像时,当前不会保留源文件系统中存储的任何扩展属性。
话虽这么说,已安装的 DwarFS 映像的根 inode 目前在 Linux 上公开了一两个扩展属性:
$ attr -l mnt
Attribute "dwarfs.driver.pid" has a 4 byte value for mnt
Attribute "dwarfs.driver.perfmon" has a 4849 byte value for mnt
dwarfs.driver.pid
属性仅包含 DwarFS FUSE 驱动程序的 PID。 dwarfs.driver.perfmon
属性包含性能监视器的当前结果。
此外,每个常规文件都会公开一个属性dwarfs.inodeinfo
其中包含有关底层 inode 的信息:
$ attr -l "05 Disappear.caf"
Attribute "dwarfs.inodeinfo" has a 448 byte value for 05 Disappear.caf
该属性包含一个 JSON 对象,其中包含有关底层 inode 的信息:
$ attr -qg dwarfs.inodeinfo "05 Disappear.caf"
{
"chunks": [
{
"block": 2,
"category": "pcmaudio/metadata",
"offset": 270976,
"size": 4096
},
{
"block": 414,
"category": "pcmaudio/waveform",
"offset": 37594368,
"size": 29514492
},
{
"block": 419,
"category": "pcmaudio/waveform",
"offset": 0,
"size": 29385468
}
],
"gid": 100,
"mode": 33188,
"modestring": "----rw-r--r--",
"uid": 1000
}
例如,这对于检查特定文件如何分布在多个块中或已将哪些类别分配给该文件很有用。
SquashFS、 xz
、 lrzip
、 zpaq
和wimlib
测试均在 8 核 Intel(R) Xeon(R) E-2286M CPU @ 2.40GHz 和 64 GiB RAM 上完成。
Cromfs 测试是在 6 核 Intel(R) Xeon(R) CPU D-1528 @ 1.90GHz 和 64 GiB RAM 上使用旧版本的 DwarFS 完成的。
EROFS 测试是在具有 64 GiB RAM 的 Intel(R) Core(TM) i9-13900K 上使用 DwarFS v0.9.8 和 EROFS v1.7.1 完成的。
在所有测试期间,系统大部分处于闲置状态。
源目录包含来自 284 个不同版本的1139 个不同的 Perl 安装,1,927,501 个文件和 330,733 个目录中总共 47.65 GiB 的数据。源目录刚刚从 tar 存档解压到 970 EVO Plus 2TB NVME 驱动器上的 XFS 分区,因此其大部分内容可能已被缓存。
我对 SquashFS 使用相同的压缩类型和压缩级别,这是 DwarFS 的默认设置:
$ time mksquashfs install perl-install.squashfs -comp zstd -Xcompression-level 22
Parallel mksquashfs: Using 16 processors
Creating 4.0 filesystem on perl-install-zstd.squashfs, block size 131072.
[=========================================================/] 2107401/2107401 100%
Exportable Squashfs 4.0 filesystem, zstd compressed, data block size 131072
compressed data, compressed metadata, compressed fragments,
compressed xattrs, compressed ids
duplicates are removed
Filesystem size 4637597.63 Kbytes (4528.90 Mbytes)
9.29% of uncompressed filesystem size (49922299.04 Kbytes)
Inode table size 19100802 bytes (18653.13 Kbytes)
26.06% of uncompressed inode table size (73307702 bytes)
Directory table size 19128340 bytes (18680.02 Kbytes)
46.28% of uncompressed directory table size (41335540 bytes)
Number of duplicate files found 1780387
Number of inodes 2255794
Number of files 1925061
Number of fragments 28713
Number of symbolic links 0
Number of device nodes 0
Number of fifo nodes 0
Number of socket nodes 0
Number of directories 330733
Number of ids (unique uids + gids) 2
Number of uids 1
mhx (1000)
Number of gids 1
users (100)
real 32m54.713s
user 501m46.382s
sys 0m58.528s
对于 DwarFS,我坚持使用默认值:
$ time mkdwarfs -i install -o perl-install.dwarfs
I 11:33:33.310931 scanning install
I 11:33:39.026712 waiting for background scanners...
I 11:33:50.681305 assigning directory and link inodes...
I 11:33:50.888441 finding duplicate files...
I 11:34:01.120800 saved 28.2 GiB / 47.65 GiB in 1782826/1927501 duplicate files
I 11:34:01.122608 waiting for inode scanners...
I 11:34:12.839065 assigning device inodes...
I 11:34:12.875520 assigning pipe/socket inodes...
I 11:34:12.910431 building metadata...
I 11:34:12.910524 building blocks...
I 11:34:12.910594 saving names and links...
I 11:34:12.910691 bloom filter size: 32 KiB
I 11:34:12.910760 ordering 144675 inodes using nilsimsa similarity...
I 11:34:12.915555 nilsimsa: depth=20000 (1000), limit=255
I 11:34:13.052525 updating name and link indices...
I 11:34:13.276233 pre-sorted index (660176 name, 366179 path lookups) [360.6ms]
I 11:35:44.039375 144675 inodes ordered [91.13s]
I 11:35:44.041427 waiting for segmenting/blockifying to finish...
I 11:37:38.823902 bloom filter reject rate: 96.017% (TPR=0.244%, lookups=4740563665)
I 11:37:38.823963 segmentation matches: good=454708, bad=6819, total=464247
I 11:37:38.824005 segmentation collisions: L1=0.008%, L2=0.000% [2233254 hashes]
I 11:37:38.824038 saving chunks...
I 11:37:38.860939 saving directories...
I 11:37:41.318747 waiting for compression to finish...
I 11:38:56.046809 compressed 47.65 GiB to 430.9 MiB (ratio=0.00883101)
I 11:38:56.304922 filesystem created without errors [323s]
⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯
waiting for block compression to finish
330733 dirs, 0/2440 soft/hard links, 1927501/1927501 files, 0 other
original size: 47.65 GiB, dedupe: 28.2 GiB (1782826 files), segment: 15.19 GiB
filesystem: 4.261 GiB in 273 blocks (319178 chunks, 144675/144675 inodes)
compressed filesystem: 273 blocks/430.9 MiB written [depth: 20000]
█████████████████████████████████████████████████████████████████████████████▏100% |
real 5m23.030s
user 78m7.554s
sys 1m47.968s
因此,在此比较中,无论是 CPU 时间还是挂钟时间, mkdwarfs
都比mksquashfs
快 6 倍以上。
$ ll perl-install.*fs
-rw-r--r-- 1 mhx users 447230618 Mar 3 20:28 perl-install.dwarfs
-rw-r--r-- 1 mhx users 4748902400 Mar 3 20:10 perl-install.squashfs
在压缩比方面, DwarFS文件系统比SquashFS文件系统小10倍以上。使用 DwarFS,内容已被压缩到原始大小的 0.9% (!) 以下。此压缩率仅考虑单个文件中存储的数据,而不考虑实际使用的磁盘空间。在原始的 XFS 文件系统上,根据du
的说法,源文件夹使用了 52 GiB,因此DwarFS 镜像实际上只使用了原始空间的 0.8% 。
这是使用lzma
压缩而不是zstd
的另一个比较:
$ time mksquashfs install perl-install-lzma.squashfs -comp lzma
real 13m42.825s
user 205m40.851s
sys 3m29.088s
$ time mkdwarfs -i install -o perl-install-lzma.dwarfs -l9
real 3m43.937s
user 49m45.295s
sys 1m44.550s
$ ll perl-install-lzma.*fs
-rw-r--r-- 1 mhx users 315482627 Mar 3 21:23 perl-install-lzma.dwarfs
-rw-r--r-- 1 mhx users 3838406656 Mar 3 20:50 perl-install-lzma.squashfs
很明显,运行速度明显加快,生成的图像也明显变小。尽管如此, mkdwarfs
速度大约是 SquashFS 图像的 4 倍,并且生成的图像比 SquashFS 图像小 12 倍。 DwarFS 映像只有原始文件大小的 0.6%。
那么,为什么默认情况下不使用lzma
而不是zstd
?原因是lzma
解压速度比zstd
慢大约一个数量级。如果您只是偶尔访问压缩文件系统上的数据,这可能不是什么大问题,但如果您广泛使用它, zstd
将带来更好的性能。
上述比较并不完全公平。 mksquashfs
默认使用 128KiB 的块大小,而mkdwarfs
默认使用 16MiB 块,甚至使用-l9
的 64MiB 块。当两个文件系统使用相同的块大小时,不出所料,差异变得不那么显着:
$ time mksquashfs install perl-install-lzma-1M.squashfs -comp lzma -b 1M
real 15m43.319s
user 139m24.533s
sys 0m45.132s
$ time mkdwarfs -i install -o perl-install-lzma-1M.dwarfs -l9 -S20 -B3
real 4m25.973s
user 52m15.100s
sys 7m41.889s
$ ll perl-install*.*fs
-rw-r--r-- 1 mhx users 935953866 Mar 13 12:12 perl-install-lzma-1M.dwarfs
-rw-r--r-- 1 mhx users 3407474688 Mar 3 21:54 perl-install-lzma-1M.squashfs
即使这仍然不完全公平,因为它使用了一项功能( -B3
),该功能允许 DwarFS 引用最多两个先前文件系统块中的文件块。
但重点是,这确实是 SquashFS 的优势所在,因为它不支持更大的块大小或反向引用。正如您将在下面看到的,DwarFS 默认使用的较大块并不一定会对性能产生负面影响。
DwarFS 还提供一个选项,可以使用不同的压缩算法重新压缩现有文件系统。这非常有用,因为它允许相对快速地试验不同的算法和选项,而无需完全重建文件系统。例如,使用最佳压缩率 ( -l 9
) 重新压缩上述文件系统:
$ time mkdwarfs --recompress -i perl-install.dwarfs -o perl-lzma-re.dwarfs -l9
I 20:28:03.246534 filesystem rewrittenwithout errors [148.3s]
⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯
filesystem: 4.261 GiB in 273 blocks (0 chunks, 0 inodes)
compressed filesystem: 273/273 blocks/372.7 MiB written
████████████████████████████████████████████████████████████████████▏100%
real 2m28.279s
user 37m8.825s
sys 0m43.256s