IPADS公众号总结
背景
虚拟化是当今数据中心和云平台的支柱性技术。无数任务以虚拟机的形式存在和运行,而一项关键技术是将一个正在运行的虚拟机从一台物理机迁移到另一台,这个过长成为虚拟机的热迁移。在大型数据中心中,热迁移在每个元中都会发生数百万次。
由于ai训练等搞性能需求工作负载的兴起,数据中心正在广泛采用RDMA作为网络信道。为了让虚拟机中运行的程序可以享受到裸金属级别的性能(即不引入中间虚拟化软件层的ewd开销),现有RDMA硬件支持PCI穿透(让虚拟机内可以通过MMIO直接与PCIe设备通信)、IOMMU(在允许DMA引擎直接访问虚拟机内存的情况下实现地址空间隔离)和SR-IOV(将PCIe资源划分到多个虚拟化设备,并将他们分配到不同虚拟机)。在这些技术的支持下,虚拟机之间可以通过RDMA进行直接通信。
挑战
虽然PCI穿透可以极大增强虚拟机使用RDMA时的性能,但它却为虚拟机的热迁移带来了很大的挑战。
- 命名空间迁移:RDMA自己为通信相关的对象(如QP,MKey)维护了各自的ID。由于这些ID是硬件分配的,软件层无法在迁移后准确复现这个明明空间,因此必须增加一层在线ID翻译。这回引入对客户机操作系统或中间件的修改
- 在途网络报:由于传输状态只存在于RDMA设备内部,软件层必须在热迁移之前完成所有在途RDMA操作,这会极大增加迁移期间虚拟机的暂停时间
- 重建连接:热迁移后,由于地址和命名空间的变化,被迁移的虚拟机必须重建所有QP,这就意味着所有于这个虚拟机之前建立的连接都需要重建
解决方案
本文认为,要在保证RDMA性能和最小化downtime的前提下实现热迁移一定需要设备的协助,并列出了一系列实现原则和对应的设备支持
网络透明性
每个RDMA设备可能于成千上万的设备建立了连接,而其中只有很少一部分是正在使用的。于所有对端进行协调对热迁移来说是过于昂贵且没有必要的。
因此,本工作在RDMA设备的设计中遵循了以下原则
- 迁移时保持RDMA明明囧见不变,以避免于所有对端协调对象ID的变化
- 在迁移后精确地复现所有本地的网络地址和QP状态
- 修改RDMA连接的timeout机制为exponetial backoff,以避免迁移过程带来的通信延迟造成RDMA连接断开
- 迁移前,以单个网络报的粒度进行暂停处理,而非等待所有的在途网络包
从hypervisor访问设备内部信息
要实现热迁移对客户机操作系统的透明性,就需要允许hypervisor读取和恢复RDMA设备内部信息。逐个追踪所有RDMA对象的状态不仅会引入大量开销,而且涉及到这些对象之间的依赖,会极大增加软件设计的复杂度。因此,本工作将设备内部状态包装为一个黑河暴露给hypervisor,从而支持上层软件方便地对RDMA设备状态进行迁移。
向现有虚拟化基础架构的集成
本工作还将现有的数种虚拟机热迁移技术应用到了RDMA设备当中,包括
- 预拷贝部分较大的设备状态来缩短downtime
- 是ebwviii控制RDMA请求的处理速度,以避免迁移过程中过多内存被远端RDMA操作污染
- 将设备状态的序列化、反序列化过程于传输过程进行流水线化,减小延迟。
多设备的挂起/恢复
由于PCIe switch允许不同设备之间绕过CPU直接通信,已经挂起的设备仍然可能受到来自其它设备的通信,为了保证状态一致性,挂起和恢复操作必须被分为主动和被动两个阶段,分别由不同的指令来实现
- 主动挂起:告知设备不再进行新的DMA操作并中止所有还未发出的DMA请求,但仍可以处理到来的请求并更新自己的状态
- 被动挂起:告知设备封存所有状态并转杯被打包为镜像
- 被动恢复:将设备恢复到主动挂起状态
- 主动恢复:将设备恢复到正常状态
abstract
提出了一种迁移一组直接交互硬件设备的方法,方法对于虚拟机及其网络都透明。提出了一种基于设备的解决方案,包括
- 通用的设备-虚拟化平台接口
- 针对NVIDIA connectX系列网络适配器设计并实现的热迁移支持机制
- 一种新颖的方案,用于静默化通过内存架构(如PCIe)进行的直接通信
introduction
为了满足AI训练通信需求,RDMA设备可以直接访问访问加速器的内存,从而避免来回在不同的虚拟机内存之间切换。但是为了支持这个场景,hypervisor必须同时暂停每个直通设备,并保持每个设备间通信的一致性。
RDMA技术的特点在于其复杂的软件接口。为了应对这个挑战,早期的RDMA迁移方案采取了协调一致的RDMA资源销毁与重建机制,这在关键路径上引入了额外的开销。在另一些方案,则依赖于RDMA API和通信协议中的非标准扩展。然而,这些方案均需对客户机进行修改,但是云厂商一般不能访问租户的软件栈。
- section3中 阐述RDMA设备透明迁移至客户机软件及其网络所需遵循的原理及相应的设备支持机制。
- 扩展该方案,提出一种新颖的技术,用于静默化多个直通设备之间的直接通信
- section4中展示该技术在PCIe架构中的适用性
- 与硬件无关
- section5中,定义一个简单且通用的应用程序编程接口,用于硬件设备的迁移操作,该接口与现有虚拟化基础设施完美兼容。
- section6中,介绍实现的段都断设备辅助VM迁移方案。
- 使用connectx系列网络适配器,演示如何静默化复杂设备,并提取其硬件状态,以便在另一台设备上快速重建,同时支持关东更新
background
RDMA
- 硬件网络传输的实现(卸载任务),最小化软件开销,并支持计算与网络的独立推进
- 操作系统旁路————允许应用程序直接访问硬件,以支持数据路径操作(例如:启动数据传输并检测其完成)
- 想远程网络对等方暴露DMA,从而实现单边访问
IB Verb
InfiniBand的Verb规范,是RDMA API的事实标准,该API由RDMA对象和一组用于操作这些对象的原语组成。RDMA对象的管理(创建或修改)被视为一条控制路径,与数据路径不同,需要操作系统内核的参与。
RDMA Objects
在数据路径中,RDMA对象直接从用户空间访问,以最大限度地降低延迟。要启动数据传输,需将工作队列元素(WQE)发布到QueuePair中。传输完成是通过轮询一个CompletionQueue对象中的完成队列条目(CQE)来检测。内存区域(MR)对象用于向本地和远程DMA访问公开应用程序内存。创建MR的对象成为MemoryRegistration,并且是显著的开销所在。
RDMA namespace
创建时,RDMA对象会被分配一个整数标识符,这些标识符在于相应对象类型(如QP命名空间)关联的命名空间内是唯一的。这些标识符对客户机操作系统内核和RDMA中间件(即libibverbs)可见。此外,某些标识符,尤其是memory keys(MR Identifiers)和QP编号,还会向远程对等方公开。这些标识符通过应用程序提供的带外通道或经由RDMA连接管理协议建立的通道进行通信。
虚拟化系统中的IO
PCIe直通中,客户机软件可直接从虚拟地址空间访问内存映射(MMIO)区域与PCIe设备进行通信,为了使设备能够直接访问虚拟机(如DMA和中断)的同时保持隔离性,引入了IOMMU。为了实现单个PCIe设备在多个虚拟机之间的安全共享,PCIe SR-IOV扩展允许一个物理功能(PF)创建多个虚拟功能(VF)。后端资源由PF和VF共同共享,同时每个VF都拥有独立的PCIe资源集。在Hypervisor中,VF被视为一个独立的PCIe设备,可安全地直通到目标虚拟机。
热迁移
pre-copy
在pre-copy阶段,虚拟机状态会在目标系统上逐步重建,同时虚拟机仍继续在源端运行。最初,虚拟机内存快照会被传输到目标端。随后,经过多个预复制轮次,将自上一轮以来被修改(脏页)的内存页面逐步传输过去。为了追踪脏页,hypervisor会利用CPU的MMU。当存在直通设备时,内存还可能因为DMA操作而被修改。此时,虚拟机管理器可借助支持报告IO事务的脏位的现代IOMMU来跟踪这些页面。
stop-and-copy
略
post-copy
略
network-reconfiguration
虚拟机恢复运行后,必须通知网络基础设施其物理位置的变更。在以太网L2网络中,通常通过发送gratuitous ARP reply(gARP)来实现这个目的。而在overlay网络中,则通过SDN控制器执行集中式重构。在IB网络中,是通过重新编程虚拟端口来完成的。
RDMA迁移
虽然存在软件实现的RDMA方案,但高性能系统仍然依赖于PCI直通技术,将RDMA设备直接暴露给虚拟机。因此,设备状态对虚拟机管理程序而言变得无法访问。目前,对于KVM/QEMU,如果启用了设备直通,会禁用热迁移功能。
namespace migration
RDMA技术的特性带来了进一步的挑战。由于RDMA标识符由设备分配,软件无法在目标系统上精确复制RDMA命名空间。为了确保迁移后应用的透明性,基于软件的方法必须在运行时对资源标识符进行翻译,这通常需要对客户机操作系统活中间件进行侵入性修改。
in-flight messages
由于传输状态被封装在RDMA设备内部,为确保迁移的一致性,软件解决方案不得不通过完成所有未完成的WQE来耗尽QP。然而,这种方式会显著增加停机时间。另一种方法是探索对QP进行中断终止以实现检查点重启。尽管这种方法适用于双向通信,但会导致原子RDMA操作的状态不一致。此外,这两种方法都容易导致做无用功,因为即使是一个单独终止的WQE,也可能对应GB大小的消息。
restore connection
与其它外设不同,RDMA设备的迁移对连接的对等放是可见的。网络地址和RDMA命名空间(如QP编号、memory key)的变更,需要显式的重新创建所有连接到迁移虚拟机的IB QPs,这在现有解决方案中引入了同步依赖性。
为了解决这个问题,基于软件的方法依赖于全局协调。另一种方法是MigrOS,引入了一种新的QP状态——暂停,用于指示远程对等方本虚拟机在迁移中。然而,这种方法容易受到迁移虚拟机故障的影响,甚至可能导致QP被无限期阻塞。
RDMA设备迁移
RDMA设备复杂度高,持有大量状态信息,并需要在极大规模下提供硬件加速的卓越性能。可以认为,在确保最小化停机时间的同时满足这些期望的RDMA设备起义,必须借助设备本身的辅助功能。以下是一份具有实用价值的迁移方案所应该遵循的原则及其相关的设备辅助功能(DAs)。
网络透明
RDMA设备可能拥有数十万个已建立的连接,但同一时刻仅有一小部分处于活跃状态。在这种情况下,与所有远程对等方进行协调不仅成本高昂,而且毫无必要。此外,部分对等放可能也正在迁移。
为了应对这以问题,可对迁移计划进行全局协调。然而,这种方法需要深入了解租户的工作负责——但是云厂商并不知道——而且可能与其它流程(如滚动更新)产生冲突。此外,迁移过程本身也需要一定时间。在pre-copy阶段,已建立连接的集合可能会经历显著的变化,这使得强制保留连接的做法变得不切实际。
因此,无同步的网络透明性是实现可扩展迁移的关键。通过以下原则来实现这一目标:
DA1: RDMA命名空间的保持。RDMA命名空间包括链路层可见的QP编号和远程MR的memory key。这些值的任何更改,都需要与远程对等方进行协调。.
在目标设备上精确重建RDMA命名空间,可以消除此类协调要求,并确保迁移的虚拟机完全透明。
DA2: 本地连接保持。与RDMA命名空间(DA1)类似,设备必须精确恢复本地网络地址(即MAC/IP或者LID/GID)以及QPs的任何状态。这使得在连接生命周期的任意阶段均可实现迁移,包括连接建立和拆除过程中。
DA3: 远程连接的无缝保持。现有方法在迁移前会先断开虚拟机与其远程对等方的连接,待迁移完成后重新建立。而在这个解决方案中,则完全省区了这一步骤。然而,由于挂起的VF无法响应传入数据包,基于可靠连接的协议(TCP和IB RC传输)极易遭遇超时。尽管默认的TCP配置足以应对短暂的宕机时间,但依赖于亚秒级超时的RDMA协议却无法承受迁移操作带来的延迟。为此,采用指数回退机制来解决这一问题。最初,采用极短的超时设置,以弥补正常运行期间偶尔发生的数据包丢失现象;随后,重传之间的延迟将按指数方式逐步延长,从而从容应对迁移过程。
DA4: 以数据包粒度进入静默状态。通过耗尽通信来处理当前传输中的消息会导致做无用功,需要同步机制,并引入对网络状况的依赖(如拥塞)
相比之下,设备辅助机制允许数据包为粒度暂停处理,此时重传大小固定且可忽略不计。这种方法需要访问设备的内部状态,包括
- 当前预期的数据包序列号
- 传输op code
- 虚拟RDMA地址
- 用于重传的原子操作缓存结果
在hypervisor中访问设备状态
hypervisor负责保存和恢复设备,确保了对虚拟机内部软件的完全透明。然而,目前尚无标准接口可用于提取VF的状态。正如虚拟机管理程序在不深入分析其内存内容的情况下高效传输虚拟机内存页一样,采用类似的方法,一次性批量获取设备状态,而非逐个遍历RDMA资源
首先,我们将讨论为什么RDMA是“带状态的设备”。
architectural state
从IB架构的角度来看,RDMA设备的状态完由已分配对象的集合及其架构状态决定。通过将这一状态序列化并同时捕获对象间的跨依赖关系,转换为另一种更容易读的方式,即可生成一个可移植的镜像,该镜像能够被加载到任何RDMA设备中。
微架构状态
IB架构并未涵盖RDMA网卡的所有方面。首先,它省略了软件接口的定义,例如描述符格式或软硬件间共享的数据结构。其次,RDMA网卡并不局限于IB规范,它可能同时作为以太网网卡使用,并实现一些非标准功能(如加解密、拥塞控制)。为架构状态囊括了网卡的每一个细节,迁移后重新构建状态可确保完整功能得以保留。
DA5: 宽松的微架构状态。尽管微架构状态存在不足,但精确捕捉某一特定时刻的为状态既不可行,也缺乏效率。并非所有硬件中的状态都能被读取或恢复,而几乎捕获每个寄存器将导致镜像尺寸巨大。因此,我们主张在状态表示的精确度与内存使用之间取得一个平衡。
DA6: 黑箱状态提取。为支持与设备无关的迁移,VF状态必须被视为黑箱处理。此前关于RDMA迁移的研究主要集中在通过IB Verb或其扩展功能实现对象级别的序列化。然而,遍历RDMA对象会因每次访问资源的开销而带来额外的负担,除了性能的影响外,跟踪单个RDMA对象及其依赖关系还会显著增加软件复杂度:每种设备扩展都需要新增迁移逻辑,并相应更新API接口。
DA7: 镜像兼容的跟踪。高性能集群通常采用同构硬件构建。然而,为了bug fix或者启用新功能,仍需进行固件更新。为最大限度减少服务停机时间,云提供商通常会实施滚动升级测率,即释放部分服务器以进行维护,并借助热迁移技术实现这一过程。这带来了在不同固件版本的设备之间迁移的挑战。
我们通过引入设备迁移“标签”————一种与特定设备兼容性特征相关的厂商专属比特序列,来应对这一挑战。迁移标签会在源设备和目标设备上分别查询,并根据各厂商的特定规则在软件中进行对比。
在虚拟化基础设施中的集成
在热迁移中,通过pre-copy来隐藏大部分虚拟机状态传输的延迟。通过限制vCPU来控制虚拟机修改内存的速度,确保迁移过程的平稳。但是如果pre-copy阶段仍然无法充分减少downtime,那么可能还徐进一步引入post-copy。
DA8: pre-copy设备状态。对于具有较大状态的设备,使用pre-copy以缩短停机时间。为避免对pre-copy的轮次的持续时间产生负面影响,设备状态的增量更新不应该依赖于耗时的操作,如memory registration,连接管理和数据路径事务。
DA9: 脏速率控制。RDMA设备能够以极高的速率将虚拟机内存变脏,同时需要极低的vCPU占用。实际上,传入的RDMA写操作完全不涉及任何的vCPU。由于vCPU的限流机制不足以应对这种情况,设备必须提供一种手段来精确控制其内存访问速率。
DA10: 流水线的状态提取。虽然虚拟机内存可被hypervisor直接访问,但设备状态却无法被直接访问,必须显式的将其保存并加载到设备中。因此,设备镜像必须包括
- 从源VF获取镜像
- 把镜像传输到目标系统上。
- 在目标VF上加载镜像。
对于RDMA,镜像的大小取决于所分配的RDMA资源数量,可能高达百MB,并会随着各阶段时间的线性增加而延长整体处理时间。通过流水线化,可以降低整个镜像传输的时间消耗。
在pre-copy的早期阶段,也可以考虑引入流水线。
DA11:(optional) post-copy的支持。如果想要支持post-copy,那么需要设备支持page fault。从设备视角来看,普通的page fault(本地)与由于post-copy造成的page fault是没有区别的。
但是由于hypervisor必须要能够支持post-copy带来的page fault,那么必须通过类似于vCPU的方式一样来实现。 总而言之,本文没有实现。
多设备的挂起和恢复
要挂起虚拟机的时候,必须确保其内存、vCPU以及所有设备均已达到一致性状态。对于具备软件实现的半虚拟化设备而言,这一点是非常只管的,因为他们依赖主机资源————CPU用于推进操作&内存用于存储状态。因此能够立即且一致性地被停止。然而,物理设备的运行却与CPU存在异步性。此外,这些设备通常通过PCIe等交换式架构连接到主机,允许同时进行多个未完成的内存事务。这使得实现一致性状态的过程更为负载,尤其是在设备之间还通过PCIe P2P直接通信的情况下。
单设备的一致性
设备驱动程序依赖于PCIe排序规则来推断一致性问题。PCIe定义了两种类型的事务:posted和non-posted,他们分别生成相应的事务层数据包(TLP)。non-posted的请求TLP(如内存读和原子操作)会返回一个完成TLP,而posted的请求(如内存写入)不会返回一个完成TLP。
一般来说,对于标准(非宽松)事务,posted请求之间无法相互绕过,但可能绕过non-posted请求和完成操作。non-posted请求和完成操作在彼此之间是无序的,但不允许绕过posted请求。
由于一个posted请求的TLP无法被绕过,它会自动刷新其路径上的所有其它TLP。例如,网卡同城通过写入通知消息来向所有软件告知有新数据的到来,而这以操作也会同时刷新相应的有效载荷。我们采用双向的PCIe内存写操作来实现挂起命令:驱动程序通过MMIO向设备发送挂起请求,随后设备通过DMA将挂起响应报告回宿主机内存。
设备必须在有限时间内完成所有待处理的命令,并根据需要掌握新的内存事务。
多设备的一致性
然而,独立地将流程应用于多个设备,并不足以实现状态的一致性,。当两个活多个虚拟功能通过PCIe交换机直接通信时,这些虚拟功能将无法被连续挂起。这是因为,处于挂起状态的虚拟功能仍可能受到来自其活动PCIe对等设备的事务。然而,这些事务无法被挂起的虚拟功能正确处理,因为他们会修改虚拟功能的状态,并可能需要完成操作。
DA12: 两阶段挂起于恢复。为确保一致性,挂起和恢复操作必须分为两个阶段————主动阶段和被动阶段,并由各自独立的命令执行
- suspend-active: 指示设备停止接管新的DMA事务,并完成所有正在进行的non-posted事务。显然,之前已posted的事务可能仍处于in-flight状态。除此之外,设备仍可作为功能正常的PCIe目标设备。在处理传入事务的同时,选择性地更新内部状态。
- suspend-passive: 锁定设备状态,使其进入准备保存为镜像的模式。在此之后,任何传入事务的结果是未定义的。
- resume-passive: 将设备恢复到suspend-active状态
- resume-active: 完全恢复设备
// algorithm 1: VM-stop-and-copy// input: set of physical device descriptors// state of the suspended VMHV_SuspendVMvCPUs()
for dev in devdesc: Suspend(ACTIVE, dev)end
for dev in devdesc: Suspend(PASSIVE, dev)end
HV_SendVM_State()
for dev in devdesc: HV_SendDevState(dev)end以上就是挂起流程的算法。其中,hyervisor的功能都带有前缀HV,与设备迁移API区分开来。首先,vCPU被挂起,以确保客户机软件不会发起任何请求。然而,虚拟机内存仍可能受到设备的修改。接下来,将设备切换到suspend-active状态,确保其不会像内存活其它设备发起新的事务。所有设备都进入suspend-active阶段后,方可进入suspend-passive状态。
接下来,虚拟机的状态(即自上一轮pre-copy依赖被修改的vCPU执行状态和内存页)被传输到目标端,随后是设备镜像。
虚拟机恢复的步骤与上面相反。
以上提出的两部阶段方案也适用于其它内存架构设备,例如一个支持以下功能的NVLink:
- 在继续作为目标设备响应的同时,暂停新事务的发起
- 检测正在进行中的事务是否已完成
使PCIe架构暂停
虽然算法1给出了设备挂起顺序的概要,但它并未明确指出所有正在进行中的事务必须在设备被置于挂起-活动状态之前到达这些设备。
PCIe架构可以被表示为一个树,其中节点对应于结构中的各个组件,而边对应于连接这些组件的链路。树的根代表PCIe架构的根。叶子节点代表设备,而非叶子节点代表交换机。给定两个顶点,我们用表示A到B的路径。
设备之间的事务可能遵循两种可能的路径: (1)经由根节点的遍历(由于IOMMU转换活跨根端口操作)。(2)直接在同一个根端口下的设备之间进行(利用缓存的转换信息)。
假设在完成了激活命令后,设备有一些正在进行的posted事务发送给了B,表示为和。使用和表示来自A和C的suspend-active响应回复。而相应的,发送给B的suspend-passive请求表示为
令为A和B的最小公共祖先(LCA)。在suspend-active阶段,因为,刷新到,把放入X面向B的出端口。类似的,刷新到,因为他们都在路径上,并把置于r的面向B的转发出口上。在suspend-passive阶段,遍历,同时刷新了到B的和。最终,B执行suspend-passive命令,并且所有的in-fligh事务都已经被B知道了。
设备迁移API
基于千问提到的涉及原则,我们提出了一个hyervisor API以支持设备级迁移。该API分为三大类,分别用于查询、设备控制和镜像访问。
| 类型 | 命令 | 描述 |
|---|---|---|
| Qeury | QueryTag | 获得设备迁移标签(DA7) |
| Qeury | QueryBlockSize | 获得镜像访问粒度(DA10) |
| Device Control | PreCopy-Start | 启用pre-copy模式(开始跟踪ICM脏页) |
| Device Control | Precopy-Stop | 禁用pre-copy模式(如果迁移被中止) |
| Device Control | DevThrottle | 控制设备的脏页速率(DA9) |
| Device Control | Suspend-Active | 执行设备的suspend-active操作(DA12) |
| Device Control | Suspend-Passive | 完全挂起设备(DA12) |
| Device Control | Resume-Active | 完全恢复设备(DA12) |
| Device Control | Resume-Passive | 把设备恢复到resume-passive模式 |
| Image Access | ImageBlock-Save | 从设备获取下一个镜像块(DA6 & DA10) |
| Image Access | ImageBlock-Load | 像设备提供一个镜像块(DA6 & DA10) |
// algorithm2: VM-pre-copy// input: set of physical device descriptors (devdesc) associated tiwh the VMfor dev in devdesc: PreCopy(START, dev)end
while not HV_Converged(): levels = HV_ThrottoleLevels() GM_VMSendDirtyPages() HV_vCPUThrottole(levels[vCPU]) for dev in devdesc: HV_SendDevState(Dev) DevThrottle(dev, levels[dev]) endend// algorithm3: Function HV_SendDevState()// input: Device (dev) whose state is being sentvalid, block = ImageBlock(SAVE, FIRST, dev)while valid: HV_SendState(block) valid, block = ImageBlock(SAVE, NEXT, dev)end查询API为hypervisor提供必要的信息,以检查超千亿的可行性并预留所需内存。在迁移之前,管理程序会通过比较源设备和目标设备上通过QeuryTag获取的迁移标记,来验证VF的兼容性。QueryBlockSize定义了访问VF镜像的粒度
设备控制API管理VF的运行。PreCopy-Start和Precopy-Stop命令在pre-copy过程中用于控制VF的内部状态跟踪(由于VF修改的VM内存脏页由IOMMU外部跟踪)。DevThrottle限制VF修改VM内存的速率。算法2详细描述了在pre-copy阶段如何使用设备控制API。
在stop-and-copy阶段,Suspend-Active/Passive, Resume-Active/Passive被用于一致地挂起多个设备。
镜像访问API用于进行镜像传输。由于镜像的大小无法提前预知ImageBlock-Save/Load提供了一个迭代器接口,按照算法3中的方式来使用。该API旨在同时支持pre-copy和stop-and-copy两个阶段。在pre-copy阶段,完整迭代仅返回设备自上一次迭代依赖所跟踪的已修改状态。为了实现安全的镜像传输,我们利用了现有hypervisor中用于虚拟机内存传输的功能。
Implementation
在ConnectX-7上实现。
ConnectX-7 overview
包含一个PCI接口一个或多个RDMA物理接口,以及一组代表RDMA网卡的PCIe功能,同时还颇为被一个嵌入式交换机,用于在这些功能于端口之间路由数据包。于特定RDMA虚拟功能相关的状态分布于这些组件之中。
PCIe State(包括通用配置空间,MSI-X,错误处理及其它功能)由PCIe规范定义。在迁移过程中,虚拟机管理器负责为物理功能和虚拟功能分别重建该状态。
embedded switch包含用户内部数据包路由于转换的流规则,例如封装及包头字段修改。这些规则由SDN控制器通过与hypervisor的接口进行变成。需要注意的是,与嵌入式交换机相连的VF虚拟端口的状态被归入VF自身的状态。
VF state包括RDMA网卡逻辑(传输对象及其关联关系)以及队列、doorbell等接口。该状态被划分为虚拟机内存、hypervisor内存和设备三个部分。其中,虚拟机内存用于存放RDMA控制结构,如命令提交条目,以及QP和CQ的数据路径的descripto ring。绝大多数的VF内部状态被保存在Interconnect Context Memory,出于安全原因,位于hypervisor中。除了内存分配外,ICM完全由设备管理。瞬态执行状态(transient execution state)(例如传输计时器、服务质量(QoS)状态以及doorbell)和缓存则保存在设备的内部存储器中。
ConnectX-7的迁移支持
该实现充分靠靓装了ConnextX的以下特性。首先,宽松组件(DA5)完全由VF的ICM表示,而瞬态部分则主流在设备的内部存储器中;其次,ICM按每个VF进行分区,因此VF状态被封装起来,能够以批量方式(DA6)快速检索,且不会影响其它VF的正常运行;最后,设备为每个VF维护了一组独立的RDMA命名空间,这有效避免了明明空间冲突,并支持在目标端精确重建这些命名空间(DA1),从而避免了之前讨论的RDMA资源标识符转换开销。
我们使用了约6000行固件代码实现了所提出的迁移API。由于VF归VM所有,该迁移API通过响应的PF向hypervisor公开。
挂起VF
ICM内容代表了绝大部分的VF状态,包括
- RDMA命名空间、对象和他们的依赖关系
- 关于传输进度的信息
- 对客户机内存的引用
通过快速使用ICM达到一致性状态,并消除(提炼)冗余信息及特定位置的引用,能够高效生成可重定位的微架构快照。
suspend-active命令确保网络端和主机端的通信均被暂停。
暂停数据包处理
首先,通过将VF从嵌入式交换机断开并停止传输队列,组织新数据包的处理。接着,清楚当前正在处理的数据包,包括传输层处理、数据包数据的DMA写入操作,以及完成时间(CQE)的生成。如果中断被hypervisor屏蔽,则将其交付或暂存起来。
暂停host通信
所有暂存的未完成的操作(即由guest OS发出的、用于修改虚拟机内存的控制路径命令)均会被完成,还optionally的生成中断。在VF恢复之前,新的命令将被阻断。
当前的数据允许继续被处理,但是后续的更新将被停止。最后,禁用VF的PCIe DMA主控能力。需要注意的是,传入的PCIe请求仍会被处理,但仅处理对网卡一致性至关重要的请求,其余请求将被忽略。
suspend-passive命令通过使设备缓存失效并按照以下方式提炼其运行时状态,最终完成对VF的暂停。
刷新设备缓存
当所有VF活动的触发条件被组织,且现有异步留停止后,系统将不再发生状态变化,刷新VF设备缓存可确保ICM内容的一致性,并准确反映VF的当前状态。
提炼状态
任何在迁移后可重建或已过时的状态,均会被排除在镜像之外。其中,可重建的运行时状态能够基于冗余信息,在目标端被重新生成。例如,当前active QP及其关联的运行列表,可从QP生产者和消费者索引中恢复。而过期的状态则包括那些因时间推移或位置改变,已不再适用于目标端的元素。比如,为确保设备正常运行而校准的RDMA传输超时机制,并非设计用于应对长时间停机。再比如,表示特定网络路径的拥塞控制装疼的,在迁移完成后便毫无意义。同样地,我们也不会传输细粒度的QoS状态,例如以毫秒级速率产生并消耗的调度配额。
VF镜像控制
hypervisor通过ImageBlock-Save命令,将VF图像分段提取到已经预先分配的宿主机内存中。该镜像包含已剥离了与位置相关的全局物理资源(DA5)引用的ICM内容,例如内部VF标识符和物理端口索引。
在目标机器上,hypervisor使用ImageBlock-Load命令,将镜像段加载到一个新的VF中。PF为VF的ICM分配内存页,并填充镜像的内容,随后重新建立物理资源的关联。
恢复VF
镜像加载后,Resume-Active命令会将VF置于suspend-active状态。此时,ICM修改及传入的PCie P2P请求处理功能均被启用。
Resume-Active命令会把VF连接至嵌入式交换机,并未所有QP恢复传输队列处理。随后,系统将扫描所有QP,对于任何处于待发送状态的QP,内部会触发doorbell,并重新启动传输计时器。同时,QoS配额将作为传输流程的一部分被重新分配。
设备辅助的pre-copy
VF状态的pre-copy
在恢复过程中,hypervisor必须未目标VF的ICM分配后备存储页,这构成了主要的开销来源。我们利用pre-copy API将源VF的ICM布局信息传递给目标VF,并在挂起VF之前预先分配好后背页面。而在stop-and-copy阶段,仅需分配剩余的一小部分ICM页面,并通过VF镜像段来填充ICM内容
脏页速率限制
未控制RDMA设备污染host内存速率,使用ConnectX的流量整形功能来限制传入流量的速率。
设备兼容性
在我们的实现中,由QueryTag命令返回的迁移标签涵盖了ICM布局版本、功能集以及资源容量。可通过严格或宽松策略,强制确保源VF于目标VF之间这些组件的一致性。在严格策略下,ICM布局及相近的功能和资源容量列表都必须完全匹配;然而,这回导致迁移标签体积膨胀,且仅适用于不涉及功能扩展的关键性错误修复。
相反,我们采用了一种宽松的策略:VF的功能及和容量由单一版本统一表示。较高版本意味着新增了功能或扩展了容量。当满足以下条件时,就允许迁移
- ICM布局版本完全匹配
- 目标VF的功能版本和容量版本不低于源VF的响应版本。
这以方案既支持关键性更新,也支持功能性更新,同时确保目标VF能够兼容软件所宣称的任何原始能力。然而,若涉及ICM布局的重大变更,则仍需执行冷重启操作。
Hypervisor的驱动
传统上来说,PCIe直通功能是通过于厂商无关的驱动程序实现的,如Linux VFIO,它负责管理VF,并依赖PCIe规范将任意PCIe设备暴露给虚拟机,由于迁移功能并不属于PCIe规范的一部分,VFIO需要特定于厂商的代码来支持设备的热迁移。因此,我们基于所提出的于厂商无关的迁移API,未VFIO驱动程序扩展了一套模块化基础设施。
ConnextX-7的热迁移由mlx5-vfio-pci VFIO插件提供。该插件实现了通用基础设施于ConnextX-7驱动程序(mlx5_core模块)之间的桥接,后者回将热迁移调用转发至PF接口。此VFIO驱动的扩展以及mlx5-vfio-pci插件的实现需要大概3000行代码,自linux 6.7版本其正式发布。
虚拟机管理软件
QEMU是一个开源的广泛使用的hypervisor。我们通过以下方式实现了PCIe直通设备的迁移支持
- 集成了VFIO驱动程序提供的全新迁移功能
- 扩展了迁移基础设施,以充分利用pre-copy和流水线式的镜像传输
其中,Qemu设备热迁移支持所需的代码量约1K行,并已从Qemu8.1版本开始提供。借助相同的直通迁移基础设施于API,后续还将开发诸如NVMe和GPU的支持。