共计 6540 个字符,预计需要花费 17 分钟才能阅读完成。
文 / 阿里云内核存储团队,龙蜥社区高性能存储技术 SIG 成员
容器化是最近几年 devops 界风行的趋势,通过业务的容器化咱们将创立一个齐全打包、自蕴含的计算环境,让软件开发人员可能更加疾速地创立和部署本人的应用程序。然而长期以来,因为镜像格局的限度,容器启动镜像的加载是很慢的,相干背景细节能够参考“容器技术之容器镜像篇”。为了减速容器的启动,咱们能够将优化后的容器镜像搭配 P2P 网络等技术,从而无效升高容器部署启动的工夫,并可保障容器继续稳固运行,“让容器利用治理更快更平安,Dragonfly 公布 Nydus 容器镜像减速服务”。
除了启动速度,镜像分层、去重、压缩、按需加载等外围个性在容器镜像畛域也尤为重要。然而因为没有原生的文件系统反对,大多数都抉择了用户态计划,Nydus 最后亦如此。随着计划和需要的一直演进,用户态计划遇到了越来越多的挑战,如性能与原生文件系统相比有较大差距、高密场景下资源开销较大等等。究其原因,次要是在用户态实现镜像格局的解析、按需加载等操作,将带来大量内核态 / 用户态通信开销。所以看起来解决了启动速度,这些外围性能的研发就会有不小的挑战,有点顾此失彼。
那么有没有可能做到鱼和熊掌兼得呢?为此,龙蜥社区做了一个大胆的尝试,咱们设计并实现了兼容内核原生 EROFS 文件系统的 RAFS v6 格局,心愿将容器镜像计划下沉到内核态。同时为了一劳永逸,咱们也尝试将这个计划推动到内核主线以让更多的人收益。最终,随着 Linux 内核各位大佬的挑战和咱们的不断完善,erofs over fscache 按需加载技术终于被合入 5.19 内核(链接见文末),至此 Nydus 镜像服务的下一代容器镜像散发计划逐步清晰起来。这也是 Linux 主线内核首个原生反对、开箱即用的容器镜像散发计划,容器镜像的高密、高性能、高可用和易用性从此不再是个问题!作者为此也给本人加了个鸡腿,哈哈!
本文将从 Nydus 架构回顾、RAFS v6 镜像格局和 EROFS over Fscache 按需加载技术三个角度来别离介绍这一技术的演变历程,并通过比照数据展现了以后计划的卓越性能,心愿大家可能尽早享受到容器启动飞一样的体验!
一、Nydus 架构回顾
一句话总结一下,Nydus 镜像减速服务是一种优化了现有的 OCIv1 容器镜像架构,设计了 RAFS (Registry Acceleration File System) 磁盘格式,最终出现为一种文件系统的容器镜像格局的镜像减速实现。
容器镜像的基本需要,实质上是为了提供容器的根目录 (rootfs),这能够通过文件系统 (file system) 或者是归档格局 (archive format) 来承载,当然也能够在文件系统的根底上二次套娃 (例如通过自定义的块格局来承载),但实质载体是一个目录树,体现为文件接口。
先看一下 OCIv1 规范镜像,OCIv1 格局是一种基于 Docker Image Manifest Version 2 Schema 2 格局的镜像格局标准,由 manifest、镜像索引 (optional)、一系列容器镜像层及配置文件组成,细节能够参见相干文档,本文不再赘述。实质上说 OCI 镜像是一个以层为根本单位的镜像格局,每个层存储了文件级别的 diff data,以 tgz 归档格局存储,如下所示:
因为 tgz 的限度,OCIv1 存在一些固有问题,例如无奈按需加载、较粗的层级的去重粒度、每层 hash 值易变等等。
而一些“二次套娃”计划 (例如基于自定义块格局的容器镜像计划),也存在一些原理性的设计缺点。例如:
- 容器镜像最终要体现为一棵目录树,那么就须要相应的文件系统来承载 (例如 ext4),这样整个链路为“自定义块格局 + 用户态块设施 + 文件系统”,绝对于文件系统计划其链路更长更简单,端到端稳定性不可控;
- 因为块格局对下层的文件系统不感知,无奈辨别文件系统的元数据和数据并别离解决 (例如压缩);
- 无奈实现基于文件的镜像剖析个性例如平安扫描、热点剖析和运行时拦挡等;
- 对于多个“二次套娃”容器镜像,无奈做到不批改 blob 内容间接 merge 成一个大镜像,也无奈做到不批改 blob 内容的状况下筛选局部文件造成一个子镜像,而这是文件系统计划的人造能力。
而咱们实现的 Nydus 则是一种基于文件系统的容器镜像存储计划。其中将容器镜像文件零碎的数据 (blobs) 和元数据 (bootstrap) 拆散,让原来的镜像层只存储文件的数据局部。并且把文件以 chunk 为粒度宰割,每层 blob 存储对应的 chunk 数据;因为采纳了 chunk 粒度,这细化了去重粒度,chunk 级去重让层与层之间,镜像与镜像之间共享数据更容易,也更容易实现按需加载。因为元数据被独自分离出来合为一处,因而对于元数据的拜访不需拉取对应的 blob 数据,须要拉取的数据量要小很多,I/O 效率更高。Nydus RAFS 镜像格局如下图所示:
二、RAFS v6 镜像格局
2.1 RAFS 镜像格局演变
在 RAFS v6 格局引入之前,Nydus 应用的是一个齐全用户态实现的镜像格局,通过 FUSE 或 virtiofs 接口提供服务。但用户态文件系统计划在设计上存在以下缺点:
- 大量零碎调用开销不可疏忽,例如深度为 1 的随机小 I/O 拜访;
- 当容器镜像中存在大量文件时,频繁的文件操作会产生大量的 fuse 申请,造成内核态 / 用户态上下文的频繁切换,造成性能瓶颈;
- 非 FSDAX 场景下,用户态到内核态的 buffer copy 会耗费 CPU 占用;
- 在 FSDAX (virtiofs 作为接口) 场景下,大量小文件会大量占用 DAX window 资源,存在潜在的性能抖动;频繁切换拜访小文件也会产生大量 DAX mapping setup 开销。
这些问题是用户态文件系统计划的人造限度带来的,而如果将容器镜像格局的实现下沉到内核态,就能够从原理上根治上述问题。因此咱们引入了 RAFS v6 镜像格局,一个依靠于内核 EROFS 文件系统,实现于内核态的容器镜像格局。
2.2 EROFS 文件系统介绍
EROFS 文件系统自 Linux 4.19 内核开始存在于 Linux 主线中,过来次要用于嵌入式和挪动终端畛域,存在于以后各大风行发行版中 (例如 Fedora、Ubuntu、Archlinux、Debian、Gentoo 等等)。用户态工具 erofs-utils 也曾经存在于这些发行版和 OIN Linux system definition 列表中,社区较沉闷。
EROFS 文件系统具备如下特色:
- 实用于多种场景的原生本地只读块文件系统,磁盘格式具备最小 I/O 单位定义;
- page-sized 块对齐的不压缩元数据;
- 通过 Tail-packing 内联技术无效节俭空间,同时维持高拜访性能;
- 数据均以块为单位寻址 (mmap I/O 敌对,不需 I/O 后处理);
- 随机拜访敌对的磁盘目录格局;
- 外围磁盘格式非常简单,且易于减少 payload,扩展性更好;
- 反对 DIRECT I/O 拜访,反对块设施、FSDAX 等多种后端;
- 同时 EROFS 预留了 boot sector,可反对 bootloader 自启动等需要。
2.3 RAFS v6 镜像格局
过来一年,阿里云内核团队对 EROFS 文件系统进行了一系列的改良与加强,拓展其在云原生下的应用场景,使其适应容器镜像存储系统的需要,最终出现为一个实现于内核态的容器镜像格局 RAFS v6。而除了将镜像格局下沉到内核态,RAFS v6 还在镜像格局上进行了一系列优化,例如块对齐、更加精简的元数据等等。
新的 RAFS v6 镜像格局如下:
改良后的 Nydus 镜像服务架构如下图所示,减少了对 (EROFS based) RAFS v6 镜像格局的反对:
三、EROFS over Fscache 按需加载技术
erofs over fscache 是阿里云内核团队为 Nydus 开发的下一代容器镜像按需加载技术,同时也是 Linux 内核原生的镜像按需加载个性,于 5.19 版本合入 Linux 内核主线。
并被 Linux 内核权威媒体 LWN.net 整合入 5.19 合并窗口高亮个性(链接地址见文末):
在此之前业界已有的按需加载简直都是用户态计划。用户态计划会波及频繁的内核态 / 用户态上下文切换,以及内核态 / 用户态之间的内存拷贝,从而造成性能瓶颈。这一问题在容器镜像曾经全副下载到本地的时候尤其突出,此时容器运行过程中波及的文件拜访,都还是会陷出到用户态的服务过程。
事实上咱们能够将按需加载的 1) 缓存治理和 2) 缓存未命中的时候,通过各种路径 (例如网络) 获取数据,这两个操作解耦开。缓存治理能够下沉到内核态执行,这样当镜像在本地 ready 的时候,就能够防止内核态 / 用户态上下文的切换。而这也正是 erofs over fscache 技术的价值所在。
3.1 计划原理
fscache/cachefiles (以下统称 fscache) 是 Linux 零碎中绝对成熟的文件缓存计划,广泛应用于网络文件系统 (例如 NFS、Ceph 等)。咱们对其进行了性能加强与拓展,使其反对本地文件系统 (例如 erofs) 的按需加载个性。在该计划中,fscache 接管了缓存治理的工作。
此时容器在拜访容器镜像的时候,fscache 会查看以后申请的数据是否曾经缓存,如果缓存命中 (cache hit),那么间接从缓存文件读取数据。这一过程全程处于内核态之中,并不会陷出到用户态。
否则 (cache miss) 须要告诉用户态的 Nydusd 过程以解决这一拜访申请,此时容器过程会陷入睡眠期待状态;Nydusd 通过网络从远端获取数据,通过 fscache 将这些数据写入对应的缓存文件,之后告诉之前陷入睡眠期待状态的过程该申请曾经解决实现;之后容器过程即可从缓存文件读取到数据。
3.2 计划劣势
正如之前所形容的,在镜像数据曾经全副下载到本地的状况下,用户态计划会导致拜访文件的过程频繁陷出到用户态,并波及内核态 / 用户态之间的内存拷贝。而 erofs over fscache 下则不会再陷出到用户态,让按需加载真的“按需”,从而在提前下载容器镜像的场景下实现简直无损的性能和稳定性,最终取得 1) 按需加载与 2) 提前下载容器镜像这两种场景下真正对立、无损的计划。
具体来说 erofs over fscache 绝对于用户态计划具备以下劣势。
3.2.1 异步预取
容器创立之后,当容器过程尚未触发按需加载 (cache miss) 的时候,用户态的 Nydusd 就能够开始从网络下载数据并写入缓存文件,之后当容器拜访的文件地位恰好处于预取范畴内的时候,就会触发 cache hit 间接从缓存文件读取数据,而不会再陷出到用户态。用户态计划则无奈实现该优化。
3.2.2 网络 IO 优化
当触发按需加载 (cache miss) 的时候,Nydusd 能够一次性从网络下载比以后理论申请的数据量更多的数据,并将下载的数据写入缓存文件。例如容器拜访 4K 数据触发的 cache miss,而 Nydusd 理论一次性下载 1MB 数据,以减小单位文件大小的网络传输延时。之后容器拜访接下来的这 1MB 数据的时候,就不用再陷出到用户态。用户态计划则无奈实现该优化,因为即便触发 cache miss 的时候,用户态的服务过程同样实现了该优化,因为用户态计划实现的缓存治理在用户态,下一次容器拜访位于读放大范畴内的文件数据的时候,同样须要陷出到用户态以查看以后拜访的数据是否曾经缓存。
3.2.3 更佳的性能体现
当镜像数据曾经全副下载到本地的时候 (即不思考按需加载的影响),erofs over fscache 的性能体现显著优于用户态计划,同时与原生文件系统的性能相近,从而实现与原生容器镜像计划 (未实现按需加载) 相近的性能体现。以下是几个工作负载下的性能测试数据 [1]。
read/randread IO
以下是文件 read/randread buffer IO [2] 的性能比照:
“native” 示意测试文件间接位于本地的 ext4 文件系统中
“loop” 示意测试文件位于 erofs 镜像内,通过 loop 设施的 DIRECT IO 模式挂载 erofs 镜像
“fscache” 示意测试文件位于 erofs 镜像内,通过 erofs over fscache 计划挂载 erofs 镜像
“fuse” 示意挂载测试文件位于 fuse 文件系统 [3] 内
“ 性能 ” 一栏对各个模式下的性能进行归一化解决,以原生 ext4 文件系统的性能为基准,比拟其余模式下的性能
能够看到,fscache 模式下的 read/randread 性能与 loop 模式下的性能根本持平,同时要优于 fuse 模式;然而与原生 ext4 文件系统的性能仍存在肯定差距,咱们正在进一步剖析和优化,实践上该计划能够达到原生文件系统的程度。
文件元数据操作测试
通过对大量小文件执行 tar 操作 [4] 测试文件元数据操作的性能。
能够看到 erofs 格局的容器镜像的元数据性能甚至优于原生 ext4 文件系统,这是 erofs 非凡的文件系统格局导致的。因为 erofs 是一个只读 (read-only) 文件系统,因此其所有元数据能够严密排布在一起,而 ext4 作为可写文件系统,其元数据则扩散排布在多个 BG (block group) 中。
典型工作负载测试
测试 Linux 源码编译 [5] 这一典型工作负载下的性能体现。
能够看到,fscache 模式下的 Linux 编译负载性能与 loop 模式、原生 ext4 文件系统的性能根本持平,同时要优于 fuse 模式。
3.2.4 高密部署
因为 erofs over fscache 计划基于文件实现,即每个容器镜像都体现为 fscache 下的一个缓存文件,因此其人造反对高密部署的场景。例如一个典型的 node.js 容器镜像在该计划下对应 ~20 个缓存文件,那么在一个部署有上百个容器的机器中,只须要保护上千个缓存文件。
3.2.5 故障复原与热降级
当镜像文件全副下载到本地的时候,镜像中文件的拜访不再须要用户态服务过程的染指,因此用户态服务过程存在更加富余的工夫窗口来实现故障复原与热降级性能。这种场景下甚至不再须要用户态过程,从而实现与原生容器镜像计划 (未实现按需加载) 相近的稳定性体现。
3.2.6 对立的容器镜像计划
有了 RAFS v6 镜像格局和 erofs over fscache 按需加载技术,Nydus 同时实用于 runc 与 rund,作为这两种容器场景下的对立的容器镜像散发计划。
另外更重要的,erofs over fscache 是 1) 按需加载与 2) 提前下载容器镜像这两种场景下真正对立、无损的计划。一方面,它实现了按需加载个性,在容器启动的时候不须要容器镜像全副下载到本地,从而助力极致的容器启动速度。另一方面,它又完满兼容容器镜像曾经下载到本地的这一场景,在文件拜访过程中不再频繁陷出到用户态,从而实现与原生容器镜像计划 (未实现按需加载) 近乎无损的性能和稳定性体现。
四、瞻望与感激
之后咱们会对 erofs over fscache 计划进行继续迭代与欠缺,例如不同容器之间的镜像复用、FSDAX 反对以及性能优化等。
此外,目前 erofs over fscache 计划曾经合入 Linux 5.19 主线,后续咱们也会将该计划回合到 OpenAnolis (5.10 和 4.19 内核),使得龙蜥内核真正开箱可用,届时欢送大家应用。
最初感激计划开发过程中反对和帮忙过咱们的所有集体与团队,感激字节跳动与快手的同学对该计划的大力支持,包含但不限于社区声援、测试、代码奉献等,欢送感兴趣的小伙伴退出龙蜥社区 SIG 钉钉群(搜寻群号:34264214)和 Nydus 镜像服务 钉钉群(群号:34971767)交换,让咱们携手一起构建一个更好的容器镜像生态。
[1] 测试环境 ECS ecs.i2ne.4xlarge (16 vCPU, 128 GiB Mem),本地 NVMe 盘
[2] 测试命令 “fio -ioengine=psync -bs=4k -direct=0 -rw=[read|randread] -numjobs=1”
[3] 应用 passthrough 作为 fuse daemon,e.g. “passthrough_hp <src_dir> <tgt_dir>”
[4] 测试 “tar -cf /dev/null <linux_src_dir>” 命令的执行工夫
[5] 测试 “time make -j16” 命令的执行工夫
相干链接地址可移步龙蜥公众号(OpenAnolis 龙蜥)2022 年 5 月 27 日雷同推送查看。
—— 完 ——