上篇我们分析了基于 KVM 的虚拟化迁移技术原理,通过这种虚拟化迁移技术能够提供很好的在线迁移解决方案。但是考虑到云平台环境的复杂性,以及用户需求的多样性,在迁移过程中还需要解决宿主机的选择、磁盘镜像处理、网络切换设置、以及内存磁盘压力的处理等。因此,UCloud 云平台需要对在线迁移过程进行多方面的优化,本篇文章将具体分析 UCloud 在不同应用场景下对 KVM 虚拟化迁移技术各个阶段所做的优化。
在迁移准备阶段,需要选择相同业务类型的宿主机,以便方便创建相同配置的虚拟机。该机型除了具有足够空闲内存和磁盘的物理机外,还需要考虑目标物理机的配置是否合适。特别是需要考虑 CPU 的型号和内核的版本号。
另外,考虑到迁移过程网络带宽有限,如果带宽被其他任务占用,就会使得迁移速度下降,甚至影响最终迁移的成功率。为此,除非物理机之间的网络带宽足够大,在 UCloud 平台上原则上并不允许在相同两台物理机之间进行多个并行的迁移任务,以便尽量确保在线迁移的成功率。
在线迁移过程中需要迁移虚拟机的所有磁盘和内存数据,而且虚拟机在迁移过程中并不停机,这使得需要迁移更多的增量数据。如果能够减少数据的迁移量,就能够减少迁移时间,从而更快的实现云平台的资源动态调整和故障处理。
UCloud 的虚拟机使用的是本地存储(UDisk 除外),磁盘在物理机上是以文件方式存在的,这个文件是 sparse 文件,假设虚拟机的磁盘是 100G,但实际使用了 10G,那么这个磁盘文件在物理机上只占用了 10G 空间。如图 2.1 所示,但是原生的 Qemu 在迁移磁盘时并没有保持 sparse 特性,所以这个 100G 的磁盘迁移到目标物理机上后就实际占用了 100G 空间。这个对物理机的磁盘空间来说是非常浪费的,而且还严重影响迁移的完成时间。
图 2.1 磁盘文件零块数据迁移前后示意图
图 2.2 磁盘文件零块数据迁移优化示意图
如图 2.2 所示,我们的优化方案就是在源端读到全 0 的块,就不发送到目标端,这样目标端就是跳着块来写一个文件,这样就保持了磁盘文件的 sparse 特性。同时,考虑到线上往往存在多种 Qemu 版本,还要考虑到原生的 Qemu 和打了这个 patch 的 Qemu 之间迁移机器如何保持 sparse。为此,可以通过在 Qemu 中接收磁盘数据过程判断一个块是否全部为 0,如果是就不实际写磁盘,即可解决。所有的零块数据都被跳过,不进行传输。通过上述方法就可以忽略磁盘迁移过程中的零数据,大大减少传输的数据量。最终,通过 Qemu 的这些 patch,还可以明显减少在线迁移的数据传输量和镜像文件的空间占用量。
由于 UDisk 是网络块存储,在迁移一台带有 UDisk 机器时, 迁移 UDisk 盘是没有必要的,因为这个盘可以通过网络挂到目标。为此,我们在迁移时过滤掉虚拟机的 UDisk 盘,同时对 UDisk 产品做了改造,支持多点挂载,这样就解决了这个问题,提高了迁移的效率。在迁移前目标端 DestHost 会将 UDisk 进行挂载操作,同时迁移过程中会跳过 UDisk 的传输,当迁移结束时源端 SourceHost 会将 UDisk 进行卸载,这样既避免对 UDisk 数据进行迁移,同时避免虚拟机在迁移过程中,对 UDisk 数据的访问,实现迁移过程对用户完全透明。
目前,在线迁移默认情况下它不能很好地处理内存写密集型的虚拟机。由于在线迁移过程中,用户虚拟机并不关机,这就使得迁移过程中用户会不停产生新的内存脏数据。这些新增脏数据需要通过多次迭代的增量数据迁移来传递到目标端 DestHost 上,并在预期新增脏数据传输时间少于最大停机时间时,进行最后一次停机增量数据传输,然后将虚拟机切换到目标端 DestHost。如果用户产生的脏内存数据过多,就会使得迁移的增量数据传输时间一直大于最大停机时间,使得增量传输阶段不断进行循环迭代,导致整个迁移过程无法完成。
图 2.3 内存迁移的 auto-coverge 优化
由于用户产生脏内存数据的速度与虚拟机的 vCPU 被提交运行的时间有关,因此能够减少用户虚拟机 vCPU 执行时间可以阻止用户产生过多的内存脏数据,从而让迁移数据传输得以在内存脏数据产生之前的完成。为此,我们对 Qemu 的 auto-converge 功能进行了优化,首先,我们提高了 Qemu 的 throttling 迁移速度,避免迁移速度限制迁移的完成时间。其次,我们修改了 auto-converge 的触发条件。在增量迁移数据时,如果产生脏数据的量大于上次产生传输数据量的 50%,并重复发生多次,则自动触发自动 auto-converge 功能。该功能默认情况下,将削减 20% 的虚拟机 vCPU 执行时间,也就减低用户虚机 vCPU 的执行速度,并减少新增的脏数据。在每次内存迭代开始时,它会根据之前的削减情况,决定后续削减粒度。
如果新增脏数据仍然过多,它将重复削减 10% 的许可 vCPU 的运行时间,直至削减 CPU 直至 99%,从而触发最后阶段的停机迁移,以完成迁移过程。虽然,这种优化会使得虚拟机的停机时间稍长,但是根据长期实践结果,整个迁移的停机时间仍然非常小(小于 100ms),因此这项优化对提高迁移的成功率有重要意义。
虽然 Qemu 的 auto-converge 功能可以在一定程度上解决用户内存负载对迁移的影响,提高迁移成功率。但是如果用户产生的脏数据对 vCPU 的执行速度依赖不大的话,就会使得迁移的增量数据传输时间一直大于最大停机时间,从而使得整个迁移过程无法完成。考虑到内存负载高的用户,往往会反复修改某一内存页,这些内存页面很容易被压缩。为此,可以考虑在迁移内存数据前,对这些内存进行压缩。
如图 2.4 所示,当前 Qemu 支持的 XBZRLE 压缩算法会将之前发送的内存页面维护在其内存缓存区内。在迁移内存页面时,会先查找该页面是否在其 XBZRLE 缓存内,如果在缓存内,则进行异或编码,只传输被压缩后的增量数据;如果没有,则直接传输内存页面。通过这个过程可以大大减少发送内存页面数据量,并提高内存迁移速度。
图 2.4 内存迁移的 xbzrle 压缩迁移优化
目前,UCloud 的在线迁移已经使用 XBZRLE 进行高内存负载的迁移优化。实际使用表明通过这种压缩方法可以提高高内存负载虚拟机的迁移成功率、并缩短迁移时间,同时 CPU 使用率提高也在合理范围内;而且对于普通内存负载虚拟机的迁移,几乎没有额外的 CPU 使用率消耗。后续还会结合底层硬件加速卡,并适时的开启多线程内存压缩迁移优化。
迁移的过程是由 Qemu 来具体执行,但是对于整个迁移过程的控制则是来自更上层的 Libvirt。当 Qemu 在执行最后一步机器数据迁移切换时,两边的虚拟机都是处于 paused 状态。后续 Libvirt 将关闭源端 SourceHost 上的被迁移虚拟机,并拉起目标端 DestHost 上的对应虚拟机。在线迁移的最大优点在于不能因为迁移失败而导致虚拟机关机,不管成功或者失败,都要保障虚拟机实例的存活(源端或目标端)。
为了加强迁移过程的保障,避免源端和目标端关机的情况出现,我们将 Libvirt 中迁移过程源端开关机的控制逻辑移到 UCloud 自身的运维管理平台中,以便在出现迁移异常时,及时恢复源端 SourceHost 上的虚拟机。这个改造上线以来,多年未出现过由于迁移导致虚拟机宕机的情况。
此外,我们在迁移过程中观察到,在迁移即将完成时存在数秒网络中断的情况,这会导致用户业务出现短暂中断,使得后台的迁移过程对用户不透明。而且为减少对用户业务造成不利影响,往往需要事先和用户协调沟通迁移事项,限制了在线迁移的应用。
为此,我们通过大量的测试迁移实验发现最后一轮的虚拟机的迁移关机时间 downtime 基本在 70ms 左右,并不是长时间网络中断的主要原因,而且虚拟机内部压力和迁移速度的变化对迁移 downtime 并无明显影响。考虑到 UCloud 的虚拟机网络是采用 openswitch 来定义组建的,经过大量实验确认迁移过程中的网络中断时间和 openswtich 设置目标端虚拟机新 flow 规则的延时时间存在正相关关系。
因此,UCloud 专门为在线迁移开发了网络下发虚拟机新 flow 的接口。在虚拟机迁移后到目标端 DestHost 后,及时为虚拟机下发的新 flow 规则。通过优化 openswtich 的网络配置机制,目前已经将迁移过程中的网络中断时间控制在几百毫秒左右,基本做到用户无感知,不会因为在线迁移造成用户业务的中断。
在通过上述在线迁移优化之后,UCloud 平台上的在线迁移方案已经可以达到很好迁移成功率,为保证用户虚拟机的性能和可靠性提供了重要保障。但是,考虑到部分用户存在大容量的数据盘,如果进行正常在线迁移,整个迁移时间非常长,无法快速降低源物理机的负载,不利于资源动态调整和故障处理。特别是如果用户虚拟机正在运行高 IO 负载业务,会导致磁盘迁移过程迟迟无法结束,最终导致迁移失败。为此,UCloud 平台针对这种场景专门进行了磁盘高负载虚拟机的快速迁移优化。
考虑到正常在线迁移在目标端 DestHost 上拉起虚拟机之后,需要先通过磁盘迁移来确保目标端 DestHost 上虚拟机访问的磁盘数据和源端 SourceHost 相同。为此需要跳过磁盘迁移进行快速的迁移方案。如图 3.1 所示,首先就需要打通目标端 DestHost 和源端 SourceHost 之间的存储系统,即共享两个 Host 上虚拟机镜像的磁盘数据;同时,在此基础上进行共享存储的跨机迁移,从而实现先进行虚拟机内存和 CPU 等数据的迁移,以便在目标端 DestHost 快速拉起虚拟机,缓解源端 SourceHost 的内存和 CPU 压力。之后,再将虚拟机的大磁盘数据从源端 SourceHost 拉取到目标端 DestHost。最后,删除源 DestHost 和目标 SourceHost 直接的共享存储。具体快速在线迁移的具体实现步骤如下:
图 3.1 远程拉取磁盘数据示意图
通过快速迁移优化,整个完整的迁移过程所需的时间,和传统的迁移方法所需的时间相当。但是迁移过程中,共享存储迁移的过程非常短暂,可以快速的在目标端 DestHost 上拉起虚拟机 VM,迅速降低源端 SourceHost 的负载,改善用户 VM 之间的资源竞争,改善用户 VM 的性能,特别对于具有大数据盘的 VM 用户具有重要意义。目前,UCloud 平台的快速迁移方法已经全面上线,已经成功为众多用户完成快速跨机迁移,帮助用户解决 VM 的性能和可靠性问题。
前述各种迁移方法,通常用于相同类型的云主机之间进行迁移,特别是目标端云主机和源云主机上的虚拟机配置需要完全一致。在 UCloud 云平台,除了存在普通云主机机型外,还存在类似方舟机型、SSD 机型等许多不同存储类型的虚拟机,这些不同类型的云主机上所使用的虚拟机的磁盘配置并不完全相同。当用户存在这种机型切换要求时,以往的做法往往需要对用户虚拟机停机进行机型类型转换迁移,造成用户业务中断,不利于用户根据不同业务需要进行不同机型切换。但是当用户提出这种跨机型迁移需求时,往往伴随着其关键业务负载无法满足要求,或者关键业务需要在更加安全可靠的环境下运行,如果对关键业务进行停机切换往往是无法接受的,也极大的限制了云平台的弹性扩展特性。
为了满足用户的业务需求进行机型升级切换,同时不停止虚拟机保证用户业务在升级过程中继续运行,为此 UCloud 专门开发了跨机型的特殊在线迁移方案。针对这种跨机型的特殊迁移,其关键点在于解决磁盘设备的类型转换问题。
在 UCloud 云平台上,用户虚拟机作为一个 Qemu 进程运行,该进程需要根据底层的磁盘镜像类型,选用不同底层块设备驱动进行数据读写。为此,在进行这种特殊跨存储迁移时,需要通过 Libvirt 的特殊配置,先在目标端建立一个不同存储类型的虚拟机(其他配置完全一样),然后再进行后续数据迁移。如图 3.2 所示,通过这种特殊配置之后,源端 Qemu 将通过 qcow2 驱动从 qcow2 磁盘文件中读取客户磁盘数据,再通过网络发送到目标端,目标端 Qemu 在接收到数据之后,通过 raw 驱动将数据写入到 lvm 块设备中。通过多次的反复迭代最终完成整个磁盘的迁移,并最终将源端普通云主机上的用户虚拟机迁移切换到目标端 SSD 机型的云主机上。
整个迁移过程对用户是透明的,不会对用户业务造成不利影响,即便目标端虚拟机迁移失败也不会影响源端用户虚拟机的正常运行。
图 3.2 跨机型迁移的存储格式变换示意图
通过这种特殊的跨机型在线迁移,目前 UCloud 平台可以实现普通云主机到 SSD 云主机的相互迁移,也可以实现普通云主机到方舟高可靠机型的相互迁移,甚至通过这种迁移实现底层磁盘类型的转换,从而方便用户根据业务需要切换不同的云主机类型,而且不需要中断线上业务,实现云平台的弹性和扩展性的提高。目前,这种跨机型的迁移技术在国内云服务提供商中算是首创,大大提高用户选择的弹性度,有利于用户按需根据业务的运营状况适时的选择不同的云服务。
通过 UCloud 云平台的在线迁移方法,可以实现用户在无感知的情况下,将用户虚拟机迁移到一个升级过的新虚拟化运行环境中,在避免中断用户业务的前提下,实现对虚拟化组件的性能优化、故障修复以及新功能上线等软件升级。然而在线迁移需要迁移用户的磁盘镜像数据,这部分花费时间占迁移时间的绝大部分。特别是大磁盘用户,进行一次跨机在线迁移所需的时间往往需要花费数小时。而且线上运行着大量的虚拟机,如果都进行在线迁移需要花费的时间成本更是非常巨大,这使得在线迁移方法无法大规模用于用户虚拟化环境的升级。
当前 UCloud 云平台的虚拟化组件就由 KVM、Qemu 和 Libvirt 等构成,而且大多数的软件升级都是通过升级 Qemu 和 Libvrit 完成。由于 Libvirt 位于虚拟化组件的最上层,它的升级不会影响正在运行的虚拟机,而且直接可生效,无需停机和迁移就可完成。而 Qemu 升级以往常需要通过在线迁移才能保证无感知的升级。考虑到磁盘迁移占迁移时间的大部分,如果能够避免磁盘的迁移就可以大大节省软件升级的时间。
为此,UCloud 云平台专门开发了本地热迁移方案,以完成对 Qemu 软件的性能优化、故障修复、漏洞修补以及新功能上线等升级功能。这种方法无需迁移虚拟机的磁盘,只进行内存迁移,从而达到快速的完成软件升级。
如图 3.3 所示,在进行本地热升级的时候,需要在本地安装新版的 Qemu_new,而原有已经运行的虚拟机 VM_old 仍然为旧版 Qemu_old,然后将创建一台相同配置的新虚拟机 VM_new,此时新建的虚拟机 VM_new 的 Qemu 版本为 Qemu_new,并且新虚拟机 VM_new 此时处于 paused 状态。
新虚拟机 VM_new 和旧虚拟机 VM_old 之间通过 socket 文件进行内存数据迁移,这个迁移过程和普通在线迁移过程一致,也是先进行一次全量的内存迁移,然后再进行多次迭代的增量内存迁移,并最终短暂停机完成最后一次的内存和虚拟机机器信息等迁移。
图 3.3 虚拟机本地迁移的内存迁移过程
当前本地热迁移方法已经在 UCloud 平台上大规模应用,在实际使用过程中,不但具有普通在线迁移的优点,而且整个迁移过程更加快速,基本上可以秒级完成用户虚拟机的 Qemu 升级,对用户基本没有影响。目前,我们已经使用本地热迁移方法解决了多个高危安全漏洞对线上 Qemu 的影响。另外,通过本地热迁移方法还实现对线上运行 Qemu 版本的精简统一,方便对 Qemu 版本的维护工作。
综上所述,目前 UCloud 虚拟化云平台已经对热迁移技术进行了全方位的优化,包括热迁移技术各个阶段的优化(宿主机的选择、磁盘和内存的优化、和网络的切换设置等)、快速迁移优化、跨存储类型迁移优化、甚至本地热升级优化等。此外,UCloud 虚拟化云平台还提供了单独迁移虚拟机的磁盘内容的磁盘漂移技术、以及针对加密盘的迁移技术。
这些迁移技术已经在 UCloud 云平台上广泛用于用户虚拟机的负载均衡、宿主机的故障处理、甚至各种虚拟化组件的在线升级等。通过这些全方位的迁移优化,极大的保证了用户虚拟机的不间断稳定运行,有力地支撑了 UCloud 虚拟化云平台的高效、弹性、高可靠性的优点。
后续我们还将继续对跨机热迁移技术的高内存负载、GPU 机型、以及其他使用新型网卡、加速卡的特殊 VM 的场景进行深入开发和优化。
今日荐文
点击下方图片即可阅读
UCloud 虚拟化在线迁移优化实践(一):KVM 虚拟化跨机迁移原理