处理稀疏镜像

https://blueprints.launchpad.net/glance-store/+spec/handle-sparse-image

一些驱动程序,如 rbd 和文件系统,支持稀疏镜像,这意味着并非真正写入空字节序列,而是仅在给定偏移量处写入数据本身。“空洞”将被存储后端自动解释为零字节,并且不会真正占用您的存储空间。

问题描述

由于 Glance 处理实例镜像,它们主要由零字节序列组成,以表示实例的整个磁盘大小。例如,8GB 的 CentOS 7 云基础镜像包含 1GB 的数据和 7GB 的空洞,因此可以显著优化存储使用率和上传时间。

当前 rbd 和文件系统驱动程序的实现依赖于 utils.chunkreadable 函数,该函数基本上会将要导入的文件分割成 CHUNK_SIZE 的块,然后将这些块直接写入后端,无论内容如何,偏移量将增加块的大小。

以下是使用 Glance 的 Ceph 后端的标准 CentOS 7 云镜像的示例

$ rbd du 9b86961e-6bf3-4d0d-99dc-7c762fe6881d
NAME                                      PROVISIONED USED
9b86961e-6bf3-4d0d-99dc-7c762fe6881d@snap       8 GiB 8 GiB
9b86961e-6bf3-4d0d-99dc-7c762fe6881d            8 GiB   0 B
<TOTAL>                                         8 GiB 8 Gi
$ rbd export 9b86961e-6bf3-4d0d-99dc-7c762fe6881d /tmp/Centos7full.raw
$ md5sum /tmp/Centos7full.raw
aae49f6f57aecb9774f399149a0b7f35 /tmp/Centos7full.raw

以及使用 qemu-img convert 或 rbd import 上传相同镜像时的相同结果

$ rbd du 437e8de0-b897-4846-96aa-aff70cd8794c
NAME                                      PROVISIONED USED
437e8de0-b897-4846-96aa-aff70cd8794c@snap       8 GiB 1008 MiB
437e8de0-b897-4846-96aa-aff70cd8794c            8 GiB      0 B
<TOTAL>                                         8 GiB 1008 MiB
$ rbd export 437e8de0-b897-4846-96aa-aff70cd8794c /tmp/Centos7sparse.raw
$ md5sum /tmp/Centos7sparse.raw
aae49f6f57aecb9774f399149a0b7f35 /tmp/Centos7sparse.raw

我们可以看到,无论镜像是否稀疏,下载文件的校验和保持不变,因此不应影响文件完整性。在两种情况下,glance image-download 命令都会生成一个非稀疏文件,因为下载过程只是从后端逐块读取文件,因此会读取零字节序列,无论文件是否稀疏。

提议的变更

我们可以进行两个连续的优化,以达到与其他导入工具(如 qemu-img)相同的结果

  • 不要在块内写入零字节序列(写入优化)

  • 依赖文件系统指令跳过空洞(读取优化)

将向 rbd 和文件系统后端添加一个新的配置选项 enable_thin_provisioning,以便操作员可以切换它。启用它将同时启用读取和写入优化。

不要在块内写入零字节序列

这种第一个优化在所有情况下都有效,无论镜像文件是否稀疏,这是 qemu-img 实现的行为。它包括检查读取的块是否仅由零字节组成,如果是这样,则增加偏移量而不向存储写入任何数据。

依赖文件系统指令跳过空洞

这种第二个优化将依赖于自内核 3.8 和 python 3.3 起可用的 syscall SEEK_HOLE 和 SEEK_DATA。它包括直接跳过空洞,甚至不读取零字节序列,这在大型镜像(如设备)的情况下可能非常长(数百 GB)。由于它依赖于 Linux 内核 syscall,较旧的 Linux 内核或 Windows 节点将只是跳过优化并像以前一样工作。

这种第二个优化只有在文件系统实际将镜像文件视为稀疏时才能工作,因此需要在导入工作流程的暂存存储上“原地”将其转换为原始文件,由转换插件执行。否则,例如通过 Glance REST API 直接发送原始文件,暂存存储的文件系统将不知道空洞的存在。

备选方案

数据模型影响

REST API 影响

安全影响

通知影响

其他最终用户影响

性能影响

写入优化

这些测试已针对通过 Web 下载镜像导入工作流程发送的 2 个 rbd 后端完成,并启用了原始转换。

对于 8GB CentOS qcow2

块大小

8MB

32MB

64MB

无稀疏上传时间

3 分 31 秒

3 分 26 秒

3 分 28 秒

有稀疏上传时间

1 分 59 秒

1 分 58 秒

2 分 04 秒

-44%

-43%

-40%

无稀疏上传使用的存储空间

8 GiB/8 GiB

8 GiB/8 GiB

8 GiB/8 GiB

有稀疏上传使用的存储空间

1.0 GiB/8 GiB

1.0 GiB/8 GiB

1.0 GiB/8 GiB

-88%

-88%

-88%

对于 200GB CentOS qcow2

块大小

8MB

无稀疏上传时间

4 小时

有稀疏上传时间

41 分 11 秒

-83%

无稀疏上传使用的存储空间

200 GiB/200 GiB

有稀疏上传使用的存储空间

5.8 GiB/200 GiB

-88%

读取优化

以下测试是通过读取 CentOS 7 镜像文件的完成的

CentOS 8GB Qcow2

CentOS 8GB RAW

CentOS 100GB Qcow2

CentOS 100GB RAW

读取整个文件(包括空洞)

0 分 3.964 秒

0 分 16.746 秒

0 分 4.666 秒

3 分 4.003 秒

仅读取数据(跳过空洞)

0 分 2.662 秒

0 分 4.686 秒

0 分 3.916 秒

0 分 4.425 秒

-32,8%

-72,0%

-16,1%

-97,6%

Qcow2 镜像的优化往往可以忽略不计,因为 Qcow2 镜像没有空洞,因此在所有情况下都应该非常快。这里的重点是表明 Qcow2 镜像没有负面影响,而原始镜像有巨大的积极影响,因此我们可以将此行为应用于所有情况。

其他部署者影响

为 rbd 和文件系统存储添加新的 enable_thin_provisioning 配置选项需要操作员启用它。如果没有此选项,行为将与以前相同。

由于此配置选项是每个存储的,因此可以在多存储环境中选择在哪个存储上启用它。

开发人员影响

无,因为这些优化由驱动程序本身处理,不应更改其接口。

实现

负责人

主要负责人

alistarle

其他贡献者

yebinama

工作项

  • 更新可以处理稀疏镜像的驱动程序:文件系统和 rbd。

依赖项

测试

  • 测试修改后的驱动程序没有功能回归。

  • 测试它不会对无法使用 SEEK_DATA/SEEK_HOLE 指令的系统产生负面影响。

文档影响

  • 记录新的配置选项 enable_thin_provisioning,用于 rbd 和文件系统驱动程序。

参考资料

原始 ceph.io 文章介绍了这些优化:https://ceph.net.cn/planet/importing-an-existing-ceph-rbd-image-into-glance/

Glance_store 中最初放弃的补丁:https://review.opendev.org/#/c/430641/

SEEK_HOLE/SEEK_DATA syscall 的 Python 实现:https://bugs.python.org/issue10142