The PuzzleFS container filesystem
By Jonathan Corbet September 25, 2023 Kangrejos ChatGPT translation https://lwn.net/Articles/945320/
差不多去年的时候,发布了一些旨在支持容器工作负载(container workload)的新文件系统类型。PuzzleFS是Ariel Miculas在2023年Kangrejos聚会上提出的一个新的选手,但它具有一些自己的特点,包括一种新颖的压缩机制和使用Rust编写的实现。
关于PuzzleFS,Miculas介绍说,这是一个不可变(immutable因此也就是只读的)文件系统,与Open Container Initiative (OCI) v2 image specification的设计目标相符。它使用内容定义进行分块(content-defined chunking 稍后会详细讨论),并且使用内容寻址(content-addressed)的数据存储,文件数据和元数据(metadata)分开存储。该项目由Tycho Andersen于2021年启动,旨在创建atomfs的后续继任者。
他说,OCI图像规范的第一个版本存在许多问题,其中许多问题在Aleksa Sarai于2019年发布的博客文章中描述。这些问题的根源都是来自依赖tar存档来保存文件系统中的层。Tar,事实证明,不适合解决容器文件系统问题。
他说,tar的格式定义很差。它没有索引;而是只有一个直接导向内容的标头(header)。使用的压缩机制意味着文件系统镜像不可寻址;因此,即使只提取一个小文件,也必须解压整个文件系统。没有针对重复数据的优化;即使是小的更改也意味着重新下载整个文件系统,尽管分成多个layer在一定程度上解决了这个问题。它是与机器相关的,因为不同系统上的目录条目可能以不同的顺序显示。缺乏一致性的表现实行(canonical representation)已经引出了许多扩展,其中许多扩展解决了相同的问题。
PuzzleFS旨在解决这些问题。文件系统镜像本身由一组放置在底层文件系统上的文件组成。与OCI镜像格式一样,存在一个顶级 index.json
文件,其中包含一组标签,每个标签代表某一个版本的文件系统,并指向一个清单文件(manifest file)。清单文件又指向镜像配置和存储在实际镜像层中的数据。其他所有内容都存储为 blobs/sha256
目录中的一组blob。
文件系统中的大多数数据都被分成可变大小的块(chunk),以内容的SHA256哈希作为文件名来存储为blob。这个分块动作本身是使用FastCDC算法进行的,该算法查找"切割点(cut points)",把数据流分为不同大小的blob。任何一个特定的流(例如文件的内容)都可以分成五个或五十个块,这取决于如何确定这些切割点;然后,每个块都以不同的blob方式落在 blobs/sha256
下,并将其哈希添加到清单中。
切割点算法本身使用滑动窗口技术。数据被逐字节地遍历,然后计算最后48字节(例如)的哈希。如果该哈希的N个最低有效字节为零,则找到了一个切割点;到那个点的数据被分开存储为一个单独的blob,并且过程重新开始。
这个算法具有一些有趣的特性,也许最引人注目的是它的去重和压缩能力。由于每个块都使用其哈希作为文件名进行存储,因此多个文件共享的块将自动共享。在传统方案中,对文件的更新将导致整个新文件都要重新被存储;这一点尤其在插入或删除几个字节的情况下尤为明显。在内容定义的块划分中,插入一个字节将只导致包含更改的块产生变化,而文件的其余部分将包含相同的块,尽管可能位于不同的偏移位置。
这一实验的结果可以通过Miculas进行的实验来观察。他从Docker Hub下载了十个不同版本的Ubuntu 22.04;它们在原始形式下需要766MB的存储空间。将它们放入带有压缩的OCI镜像格式中将其大小减小到282MB。相反,将它们全部放入PuzzleFS实例中,将大小减小到130MB—都没有使用压缩。添加压缩将整个大小缩减到53MB,相比原始大小节省了93%。
PuzzleFS的一个目标是始终提供文件系统的规范表示(canonical representation)。因此,比如就定义了生成源的遍历顺序,目录和扩展属性都按字典顺序排序。还有另一个目标是希望支持直接挂载(direct mounting)。在基于tar的格式中,必须首先将文件提取出来,存放到磁盘上,从而导致在mount镜像之前有一个短暂窗口可能出现内容被更改的情况。因此,无法保证内核看到的文件与tar存档中的文件相同。PuzzleFS没有这个提取步骤,因此不存在这个问题。
数据完整性通常都是一个重要目标。在这种情况下,无法使用dm-verity来保护整个卷;虽然文件系统是不可变的,但底层数据存储不是,因为需要能够添加新版本或layer从而添加新数据。因此,fs-verity用于验证数据存储中各个文件的完整性。在挂载特定镜像时,将提供所关注清单的哈希以供 mount
进行验证。
该项目背后的一个重要目标是避免内存安全性错误。因此,文件系统实现已用Rust编写。他说,这个选择已经从开发过程中消除了很多痛苦。
目前已经有一个可用的FUSE实现,以及一个处于概念验证状态的内核实现。内核部分依赖于一组正在分别开发的文件系统接口抽象,这些抽象应该在某个时候要合入mainline。还需要一些其他工作从而使其他依赖项(包括用于元数据存储的Cap'n Proto库)达到适合内核的状态。工作正在进行中;感兴趣的人可以在此存储库中找到当前的代码。
Miculas没有讨论的一个话题是PuzzleFS与composefs之间的相似之处,它们具有一些相似的目标。Composefs在进入主线内核方面遇到了一些困难—尽管有其他一些更改仍在进行中,有望能给出帮助。PuzzleFS具有一些composefs不具备的功能;这些是否足以使其进入上游路径更容易,目前尚不清楚。
更多信息和关于磁盘格式的详细信息,请参阅此演讲幻灯片。
[感谢Linux基金会支持我们参加此活动。]
全文完 LWN 文章遵循 CC BY-SA 4.0 许可协议。