作者:高功用存储 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 内容的情况下筛选部分文件构成一个子镜像,而这是文件体系计划的天然才能;
-
块设备+传统文件体系不支撑 rootless 挂载,而 rootless 挂载是 rootless container 的要求。
而咱们完结的Nydus 则是一种根据文件体系的容器镜像存储计划 。 其中将容器镜像文件体系的数据 (blobs) 和元数据 (bootstrap) 分离,让本来的镜像层只存储文件的数据部分。并且把文件以 chunk 为粒度切割,每层 blob 存储对应的 chunk 数据;因为采用了 chunk 粒度,这细化了去重粒度,chunk 级去重让层与层之间,镜像与镜像之间共享数据更容易,也更容易完结按需加载。因为元数据被单独分离出来合为一处,因此关于元数据的拜访不需拉取对应的 blob 数据,需求拉取的数据量要小很多,I/O 功率更高。Nydus RAFS 镜像格局如下图所示:
RAFS v6 镜像格局
RAFS 镜像格局演化
在 RAFS v6 格局引入之前,Nydus 运用的是一个彻底用户态完结的镜像格局,经过 FUSE 或 virtiofs 接口供给服务。但用户态文件体系计划在规划上存在以下缺点:
-
很多体系调用开支不行忽略,例如深度为 1 的随机小 I/O 拜访;
-
当容器镜像中存在很多文件时,频频的文件操作会发生很多的 fuse 恳求,形成内核态/用户态上下文的频频切换,形成功用瓶颈;
-
非 FSDAX 场景下,用户态到内核态的 buffer copy 会消耗 CPU 占用;
-
在 FSDAX (virtiofs 作为接口) 场景下,很多小文件会很多占用 DAX window 资源,存在潜在的功用抖动;频频切换拜访小文件也会发生很多 DAX mapping setup 开支。
这些问题是用户态文件体系计划的天然约束带来的,而假如将容器镜像格局的完结下沉到内核态,就能够从原理上彻底治愈上述问题。因而咱们引入了 RAFS v6 镜像格局,一个依托于内核 EROFS 文件体系,完结于内核态的容器镜像格局。
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 自发动等需求。
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 技能的价值所在。
计划原理
fscache/cachefiles (以下统称 fscache) 是 Linux 体系中相对老练的文件缓存计划,广泛运用于网络文件体系 (例如 NFS、Ceph 等)。咱们对其进行了功用增强与拓宽,使其支撑本地文件体系 (例如 erofs) 的按需加载特性。在该计划中,fscache 接管了缓存办理的作业。
此刻容器在拜访容器镜像的时分,fscache 会查看当时恳求的数据是否现已缓存,假如缓存射中 (cache hit),那么直接从缓存文件读取数据。这一过程全程处于内核态之中,并不会陷出到用户态。
否则 (cache miss) 需求告诉用户态的 Nydusd 进程以处理这一拜访恳求,此刻容器进程会堕入睡觉等候状况;Nydusd 经过网络从远端获取数据,经过 fscache 将这些数据写入对应的缓存文件,之后告诉之前堕入睡觉等候状况的进程该恳求现已处理完结;之后容器进程即可从缓存文件读取到数据。
计划优势
正如之前所描述的,在镜像数据现已悉数下载到本地的情况下,用户态计划会导致拜访文件的进程频频陷出到用户态,并触及内核态/用户态之间的内存复制。而 erofs over fscache 下则不会再陷出到用户态,让按需加载真的 “按需” ,然后在提前下载容器镜像的场景下完结几乎无损的功用和稳定性,终究获得 1) 按需加载与 2) 提前下载容器镜像这两种场景下真实一致、无损的计划。
具体来说 erofs over fscache 相关于用户态计划具有以下优势。
- 异步预取
容器创立之后,当容器进程没有触发按需加载 (cache miss) 的时分,用户态的 Nydusd 就能够开端从网络下载数据并写入缓存文件,之后当容器拜访的文件方位恰好处于预取范围内的时分,就会触发 cache hit 直接从缓存文件读取数据,而不会再陷出到用户态。用户态计划则无法完结该优化。
- 网络 IO 优化
当触发按需加载 (cache miss) 的时分,Nydusd 能够一次性从网络下载比当时实际恳求的数据量更多的数据,并将下载的数据写入缓存文件。例如容器拜访 4K 数据触发的 cache miss,而 Nydusd 实际一次性下载 1MB 数据,以减小单位文件巨细的网络传输延时。之后容器拜访接下来的这 1MB 数据的时分,就不必再陷出到用户态。用户态计划则无法完结该优化,因为即便触发 cache miss 的时分,用户态的服务进程同样完结了该优化,因为用户态计划完结的缓存办理在用户态,下一次容器拜访坐落读扩大范围内的文件数据的时分,同样需求陷出到用户态以查看当时拜访的数据是否现已缓存。
- 更佳的功用体现
当镜像数据现已悉数下载到本地的时分 (即不考虑按需加载的影响),erofs over fscache 的功用体现明显优于用户态计划,一同与原生文件体系的功用附近,然后完结与原生容器镜像计划 (未完结按需加载) 附近的功用体现。以下是几个作业负载下的功用测验数据 [1]。
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 文件体系的功用仍存在一定距离,咱们正在进一步分析和优化,理论上该计划能够达到原生文件体系的水平。
2、文件元数据操作测验
经过对很多小文件履行 tar 操作 [4] 测验文件元数据操作的功用。
能够看到 erofs 格局的容器镜像的元数据功用乃至优于原生 ext4 文件体系,这是 erofs 特别的文件体系格局导致的。因为 erofs 是一个只读 (read-only) 文件体系,因而其一切元数据能够紧密排布在一同,而 ext4 作为可写文件体系,其元数据则涣散排布在多个 BG (block group) 中。
3、典型作业负载测验
测验 Linux 源码编译 [5] 这一典型作业负载下的功用体现。
能够看到,fscache 形式下的 Linux 编译负载功用与 loop 形式、原生 ext4 文件体系的功用基本相等,一同要优于 fuse 形式。
- 高密布置
因为 erofs over fscache 计划根据文件完结,即每个容器镜像都体现为 fscache 下的一个缓存文件,因而其天然支撑高密布置的场景。例如一个典型的 node.js 容器镜像在该计划下对应 ~20 个缓存文件,那么在一个布置有上百个容器的机器中,只需求保护上千个缓存文件。
- 故障康复与热升级
当镜像文件悉数下载到本地的时分,镜像中文件的拜访不再需求用户态服务进程的介入,因而用户态服务进程存在愈加充裕的时刻窗口来完结故障康复与热升级功用。这种场景下乃至不再需求用户态进程,然后完结与原生容器镜像计划 (未完结按需加载) 附近的稳定性体现。
- 一致的容器镜像计划
有了 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” 指令的履行时刻
相关链接地址: 1.龙蜥社区高功用存储技能 SIG 地址:
openanolis.cn/sig/high-pe…
2.erofs over fscache 合入 5.19 内核提交链接:
git.kernel.org/pub/scm/lin…
- FUSE passthough_hp daemon:
github.com/libfuse/lib…
- Nydus image service(请咱们多多重视,欢迎奉献):
github.com/dragonflyos…
- LWN.net 报道链接:
lwn.net/SubscriberL…