LWN: QEMU中的数据变动跟踪与差分备份!

关注了就能看到更多这么棒的文章哦~

Changed-block tracking and differential backups in QEMU

November 17, 2020
This article was contributed by Kashyap Chamarthy
KVM Forum
DeepL assisted translation
https://lwn.net/Articles/837053/

存储虚拟化(storage virtualization)方面,有许多功能:QEMU Copy-On-Write (QCOW2) disk-image file format,disk image chain,point-in-time snapshot,backup,等等。这些功能主要是由开源的仿真器和模拟器(emulator and virtualizer) QEMU 中的 block layer 来实现的。在最近结束的 2020 KVM 论坛在线会议上,Eric Blake 就 QEMU 和 libvirt 目前在做的改进差分备份的功能进行了介绍。顾名思义,"差分备份(differential backup)" 解决了全盘备份方式的效率问题,既减少了空间占用,也加快了备份速度。

还有一个听起来类似的词,"增量备份(incremental backups)"。区别在于,差分备份主要是根据任选的某一次备份,来检测后来发生的变化。而增量备份只关注最后一次备份之后出现的变化。增量备份是差分备份的一个子集,但两者经常都被称为 "incremental backup" 。本文会使用 "差分备份" ,因为它的含义更加广泛。

建立差分备份的时候,两个版本中总有一个是当前的版本。换句话说,它不像 Git。Git 环境中,如果一个文件的最新版本比如说是 v4,那么你仍然可以在 v2 和 v3 之间进行差分比较。而在差分备份这种应用场景中,两个差分点中一定有一个是 v4,也就是当前的时间点。

QEMU 的 block layer 代码很早以前已经支持完整备份了。这个功能主要用于进行虚拟机整个存储的实时迁移,或者用于实时快照(point-in-time snapshot)。但是在过去的几年里,QEMU 和 libvirt 加快了让差分备份默认启用的开发步伐。

QCOW2 "backing chains"

QCOW2 的设计理念,是将稀疏映像文件(sparse image file)与其他作为 overlay 的文件映像结合起来,这就是所谓的 "backing chains"了。如果在 overlay 中找不到的数据,就会自动去另一个映像文件 image 中查找,也就是所谓的 "backing file"。每个 QCOW2 文件都被默认分割成 64KB 的数据 cluster,如果某个 cluster 不在 overlay 中,那么就需要去 backing file 中获取。下面是一个简单的 backing chain 的例子:

base.raw
    Overlay1.qcow2 (live QEMU)

base.raw 是 overlay1.qcow2 这个文件的 backing file。如果某个数据块是在 overlay 中分配的,那么 QEMU 将从 overlay 读取,否则的话就会从 backing file 中读取。但所有的写入都会发生在 overlay 中,所以叫 "COW(copy on write)":写入时仅使用副本(即 overlay)。注意,base image 可以是 raw 格式的,也可以是 QCOW2 格式的;而 overlay 文件则必须是 QCOW2 格式。也可以使用多个 overlay 叠加起来,称为 a chain of overlays:

base.raw
    overlay1.qcow2
  overlay2.qcow2
      overlay3.qcow2 (live QEMU)

在这种情况下,guest 发起的任何写入操作都发生在最后一个 overlay 里,也就是 overlay3.qcow2。这种 backing chain 的一个常见用法,就是基于某个 "完美的" 磁盘映像文件生成许多个副本来分别执行。还可以用在 thin provisioning(瘦配置)、point-in-time snapshot(时间点快照),以及 disk image backup(磁盘映像备份)。

Bitmaps to track "dirty" blocks

差分备份的核心,是要能在磁盘映像文件的生命周期内持续追踪哪些数据块被修改过,也称为 changed-block tracking(CBT)。我们在 QCOW2 这种块设备文件中会使用 bitmap 或者 bit array 来跟踪记录这些被修改过的部分。QEMU 在进行差分备份的时候,会利用 bitmap 来决定需要从这个虚拟磁盘映像文件(virtual disk image)中复制出来哪些部分。它提供了一组 API 来管理这个 bitmap 的生命周期,这组 API 就是 QEMU Monitor Protocol (QMP) 命令。

Blake 指出,在 QEMU 中使用 in-memory bitmap 并不是什么新鲜事:早在 2012 年,QEMU 内部首次使用 bitmap 来实现 QEMU 的一个已经用了很久的块设备的功能:block-stream。这个功能,是在 guest 运行起来之后,通过把 QCOW2 disk image chain 动态合并起来,从而提高 I/O 性能。QEMU 还扩展了 QCOW2 format specification,定义了一种“persistent bitmap”,可以存放在 QCOW2 disk image 中。当 guest OS 被关闭时,内存中的 bitmap 就会被写入到磁盘上,并在 guest 下次启动时重新加载起来,因此,这些改动的差分记录,可以不受限于 guest 的一次开机时间。

虽然 bitmap 提供了很多灵活性,但 libvirt 开发者意识到管理 bitmap 可能会变得非常困难,尤其是在涉及很长的 backing chain 的时候。人们必须小心翼翼地管理 bitmap,在合适的时机来 enable、disable 或进行合并。正是由于跟踪 bitmap 很复杂,导致他们管理 bitmap 的思路也发生了多次变化。

"checkpoint" 是 libvirt 的术语,指的是一个时间点,创建备份的时候可以针对这个时间点来创建差分备份。而 bitmap 则是跟踪一段时间内的变化。两者都是同时创建出来的,但 checkpoint 是不可以改动的,而 bitmap 将随着 guest 系统的后续操作来不断改变。最初的 libvirt 实现方案(当时涉及了多个 bitmap)试图规定无论有多少个 checkpoint,任意时刻只能有一个 bitmap 生效,从而来减少 bitmap 引入的写入开销。但 libvirt 开发者最终达成一致,认为所有的 checkpoint 都有自己的 active bitmap,这样一来,优化多个并发的 bitmap write 操作的麻烦工作就交给了 QEMU,但 libvirt 这边就不再需要花费太多精力来管理 bitmap 了。

Revitalized NBD

network block device,也就是网络块设备(NBD)。这个协议最早是在 二十三年前推出的 (Linux 2.1.55,即 1997 年 4 月),作为通过网络来访问块设备(block device)的一种方式。该协议一开始只有两个简单的命令。一个用于读取 block,另一个用于写入。但是,在过去的几年里,NBD 协议凭借新的虚拟化使用场景得到了很大发展。例如,可以通过 NBD 查询 dirty block,从而能够进行更细粒度的差分备份,特别是我们后面要进一步讨论的 "pull-based" 工作模式。有关 NBD 的更多信息,请参考 Blake 和 Richard W.M. Jones 在 2019 年 KVM 论坛上的 "Making the Most of NBD "演讲(https://www.youtube.com/watch?v=PMa6KFX9AxM)。

早在 2008 年,QEMU 就支持作为 NBD 的客户端,以便能够连接到独立的 NBD 服务器,如 qemu-nbd(或更强大的 nbdkit 服务器)并访问远程 block device。后来,QEMU 也提供了内置的 NBD server,这样一来它就可以把 disk image 以 NBD 磁盘的形式暴露出去。QEMU 内置 NBD 服务器最常见的用途之一是允许在 non-shared storage 环境中,实时迁移 VM 的磁盘。当虚拟机运行时,数据来源这一端的 QEMU 准备传输磁盘内容。同时,数据接收方的 QEMU 启动一个 NBD 服务器来提供一个空白的网络可写入的 NBD 设备。这时,数据来源端的 QEMU 将作为 NBD 客户端,连接到这里,将 guest 的 disk image 复制过来。一旦完成数据传输,内存就完全迁移过来了,这时接收方的 QEMU 就会停止 NBD 服务,接下来就可以在这里恢复虚拟机了。

Copying out the dirty blocks: "push" vs. "pull"

QEMU 将 bitmap 和 NBD 结合起来,就可以把修改过的 data block 复制出来。这里又分为两种方法。第一种是"push mode(推送模式)",QEMU 在内部跟踪修改过的数据块(按 QCOW2 的定义就是 "dirty clusters"),当用户提出备份请求时,QEMU 会在外界某个地方来创建差分备份或完整备份,也就是说,QEMU 是将数据 "推送" 给目的地。对于某些使用场景来说,QEMU 在这里可能是一个瓶颈,因为需要它来控制整个备份创建机制。

在另一种 "pull mode" 中,QEMU 将需要写出去的数据暴露出来,这是通过 QEMU 内置的 NBD 服务器实现的,把修改后的 block 暴露出来,这样就允许第三方工具可以可靠地复制出去(即数据从 QEMU 中被 "拉" 出来)。因此,pull mode 是让外部工具在它认为合适的情况下获取修改的数据,而不是等待 QEMU 将完整的备份推送到目标位置,从而避免了上面提到的性能瓶颈。

Blake 的演讲中展示了好几个使用场景。其中一个例子是如何跟踪 QCOW2 文件的 "dirty" block。这里涉及到创建一个 bitmap(使用新近添加的 qemu-img 这个 bitmap 命令),并将其添加到一个运行着 Fedora guest 的 QCOW2 映像上。现在,bitmap 就可以跟踪 guest 发起的任意写入操作了。然后,他对 disk image 进行了一些写入操作(使用 libguestfs 的 guestfish 工具),并把这些 bitmap 通过独立的 QEMU NBD 服务器 qemu-nbd 暴露出来。最后,他使用了 nbdinfo –map(一个新的命令,是 libnbd NBD 客户端库的一部分),检查暴露出来的 dirty map,看看 QCOW2 镜像的哪些区域是脏的。这使得客户端工具可以有选择地只复制出被修改的数据块。其他的演示包括如何把 bitmap 和 overlay 结合起来,以及 push 和 pull 的备份流程。

"只要 guest 数据没有被破坏,那么完整备份总是不会错的。这里介绍的跟踪变动过的 block 只是一种优化手段。"Blake 在演讲初期就强调。如果有一天出了问题,(例如,如果你丢失了一个 bitmap),那么备选方案就是是进行完整备份。这样一来,guest 数据并没有丢失,只是在处理 guest 数据的时候损失了一些效率。

用户对 QEMU 的备份功能感到放心的话(包括如何备份、以及是否选择 QCOW2 格式),那么可以使用 push 方式的备份。但是,pull 方式的备份就使得我们可以利用任何其他备份框架了,只要允许这些备份框架来控制如何以及何时准确地复制出 dirty block 就好。

Conclusion

截至本文撰写时,支持差分备份的主要功能都合入 QEMU 5.2(2020 年 12 月到期)中了。QEMU 6.0(将于 2021 年初发布)的一个改进目标就是可以动态控制打开 backing chain,允许 libvirt 把那些过长的 QCOW2 disk-image chain 给缩短(这个动作名为"block commit"),这样就可以在 backing chain 里面依旧保持 bitmap 的语义不变。

差分备份现在仍然是 libvirt 的一个 "opt-in" 功能。要想默认开启,还需要等待最终的 QEMU 接口被标记为 stable 才行。大家还在努力争取推送到 upstream。

早在 2015 年的 KVM 论坛上,差分备份的初始设计就被首次提出(John Snow 和 Vladimir Sementsov-Ogievskiy 撰写的 "Incremental Backups - Good things come in small packages"),2016 年(Max Reitz 撰写的 Backups (and snapshots) with QEMU)和 2018 年(Blake 撰写的 "Facilitating Incremental Backup")的文章都是相应的后续工作。从那时起,QEMU 和 libvirt 的 block layer 进行了许多改动,包括对 block device 的配置方式进行了重大的重新设计。所有这些,加上最近在 QEMU 中改进 bitmap 处理和 NBD 支持的工作,开辟了与备份相关的新的使用场景。这包括可以让第三方的备份客户端采取 pull 方式进行备份,并在 QEMU 和 libvirt 软件栈之上提供 changed-block tracking 方案。现在,只需要一个能够读取 bitmap 的 NBD 客户端,然后就可以用自己喜欢的方式来处理数据了。最近的项目,比如 libnbd(2019 年开始),会让编写这样的 NBD 客户端的工作变得更加容易。

[我要感谢 Eric Blake 对本文的严格审查] 。

全文完
LWN 文章遵循 CC BY-SA 4.0 许可协议。

欢迎分享、转载及基于现有协议再创作~

长按下面二维码关注,关注 LWN 深度文章以及开源社区的各种新近言论~

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值