第八篇讨论了 vhost-user。本篇看 virtio 与 live migration:迁移一台 VM 时,virtio 设备要保存什么状态?为什么只复制 guest RAM 不够?vhost backend 又如何让迁移变得更复杂?
1. 迁移为什么涉及 virtio
Live migration 不只是复制 guest RAM。
一台正在运行的虚拟机还包含设备状态。
对于 virtio 设备来说,这些状态包括:
- device status
- negotiated features
- config space
- queue state
- avail/used ring index
- pending interrupt
- in-flight request
- device-specific state
- backend state
如果这些状态没有正确保存和恢复,target 上的 guest driver 可能看到一个不一致的设备。
后果可能是:
- I/O 请求丢失
- I/O 请求重复完成
- driver 等不到中断
- queue index 错乱
- 设备被 guest 认为故障
- 文件系统或网络状态异常
2. virtio 迁移的目标
迁移目标不是让 target 上的设备重新初始化。
而是让 guest 觉得设备只是暂停了一小段时间。
迁移前:
Guest driver owns virtqueue state QEMU device model owns device state backend may own in-flight I/O state迁移后:
Guest driver continues from same queue state Target QEMU restores same device state Target backend resumes compatible data plane所以迁移保存的是 guest 可见语义,而不是 source host 的所有内部实现细节。
3. virtio common state
所有 virtio 设备都有一些 common state。
典型包括:
device status negotiated feature bits queue enable state queue size queue addresses last_avail_idx used_idx or shadow state interrupt status config generation这些状态决定 guest driver 和 device model 对设备进度的共同理解。
例如:
Guest 认为 queue 已经提交到 avail idx 100 QEMU 恢复后却认为只处理到 80这种不一致会导致请求重复处理或卡住。
4. device-specific state
不同 virtio 设备还有自己的状态。
virtio-blk 可能涉及:
- pending block requests
- write cache state
- device configuration
- request throttling state
- block backend relation
virtio-net 可能涉及:
- MAC address
- link status
- offload configuration
- multiqueue state
- control queue state
- pending packets
- RX/TX queue state
virtio-balloon 可能涉及:
- balloon size
- reported pages
- free page hinting state
这些状态不是 virtio core 能完全理解的,需要具体设备自己参与 migration。
5. queue state 为什么关键
virtqueue 是 guest 和 device 之间的共享进度条。
迁移时最关键的是两边对 queue index 的理解必须一致。
简化模型:
Guest avail ring: guest 已提交到哪里 Device last_avail_idx: device 已经消费到哪里 Used ring: device 已经完成到哪里如果 target 恢复后last_avail_idx错了,可能出现两种问题:
太小: 重复处理已经处理过的 descriptor 太大: 跳过还没处理的 descriptor所以 queue state 是迁移状态中的核心。
6. in-flight request
迁移最难处理的是 in-flight request。
所谓 in-flight,就是请求已经离开 virtqueue,正在 backend 中处理,但还没有向 guest 完成。
例如:
Guest submits block write | v QEMU sends request to host storage backend | | migration starts before completion v request is in-flight此时不能简单丢掉请求。
也不能在 source 和 target 上重复执行。
QEMU 需要让设备进入可迁移状态,例如:
- 等待请求完成
- 暂停数据面
- 记录 in-flight descriptor
- 与 backend 协调 inflight state
- 在 target 上恢复或重新提交
具体策略取决于设备和 backend 能力。
7. pending interrupt
迁移不能丢中断。
比如一个 virtio 请求已经完成,used ring 已经写了,但 guest 还没处理中断。
状态是:
used ring updated interrupt pending Guest has not handled completion yet如果迁移后 pending interrupt 丢失,guest 可能永远不知道请求完成。
如果重复注入,也可能导致 guest 额外进入 handler,但通常 driver 会检查 used ring 状态。
因此迁移需要保存和恢复中断 pending 语义。
8. vhost 让迁移更复杂
基础 QEMU virtio 设备中,QEMU 掌握 device model 和 queue 处理状态。
使用 vhost 后,数据面状态部分在 vhost backend 中。
例如 vhost-net:
QEMU: virtio control plane, migration orchestration vhost backend: vring processing, in-flight packets, eventfds迁移时 QEMU 需要协调 backend:
stop or pause backend | v collect vring/backend state | v serialize QEMU virtio state | v restore target backend | v resume queues如果 backend 不支持迁移所需状态,迁移可能受限或需要特殊处理。
9. vhost-user 的迁移挑战
vhost-user 比 vhost-kernel 更复杂,因为 backend 是独立用户态进程。
迁移时需要考虑:
- source backend 如何暂停
- backend 是否能导出状态
- target backend 如何启动
- vhost-user socket 如何重连
- shared memory 如何重新映射
- inflight descriptors 如何转移
- backend feature 是否兼容
如果 backend 是 DPDK 应用或用户态交换机,还要考虑外部网络状态和连接关系。
所以 vhost-user 的高性能来自灵活的数据面,但迁移需要更强的协议和工程约束。
10. target 上恢复什么
Target QEMU 恢复 virtio device 时,需要重建的是 guest 可见状态。
例如:
VirtIODevice common state VirtQueue state Device-specific state Backend connection Interrupt routing Eventfd / irqfd setup注意,target 不需要复制 source 的所有内部指针或线程状态。
它需要恢复的是 guest 继续运行所依赖的协议状态。
这和 KVM migration 中通常不迁移 source stage-2 page table 类似。
迁移 guest 可见状态,target 重建 host 本地实现细节。
11. 迁移版本兼容
QEMU 迁移还涉及版本兼容。
Source 和 target QEMU 可能不是完全相同版本。
设备迁移状态需要稳定的格式和兼容策略。
可能的问题包括:
- 新版本增加了设备字段
- feature bits 不一致
- target 不支持 source 使用的 feature
- backend 能力不同
- machine type 兼容性不同
这就是为什么生产环境通常要求 source 和 target 使用兼容 machine type、CPU model、设备配置和 QEMU 版本策略。
12. 调试迁移问题的方向
virtio 迁移问题常见表现:
迁移后磁盘 I/O hang 迁移后网络中断 迁移后 virtio driver reset device 迁移后 packet loss 增加 迁移后 guest dmesg 出现 virtqueue error 迁移阶段 downtime 异常变长排查方向:
- queue index 是否一致
- pending interrupt 是否恢复
- backend 是否正确暂停和恢复
- in-flight request 是否处理
- negotiated features 是否一致
- target 设备配置是否与 source 相同
- QEMU migration log 是否有设备状态错误
13. 源码阅读入口
本篇可以看:
hw/virtio/virtio.chw/virtio/vhost.chw/virtio/vhost-user.chw/block/virtio-blk.chw/net/virtio-net.cmigration/include/migration/
阅读问题:
VirtIODevicecommon state 如何保存?- queue state 如何进入 migration stream?
- device-specific migration fields 在哪里定义?
- virtio-net 保存了哪些额外状态?
- virtio-blk 如何处理 pending request?
- vhost backend 在迁移前如何暂停?
- target 上如何重新启用 queue 和 eventfd?
14. 本篇小结
virtio 迁移的核心是让 target 上的 guest driver 和 device model 对设备状态保持同一个理解。
除了 guest RAM,迁移还要保存 virtio common state、queue state、device-specific state、pending interrupt 和 backend/in-flight 状态。
使用 vhost 或 vhost-user 后,数据面状态不再只在 QEMU 中,迁移需要额外协调 backend。
可以把本篇压缩成一句话:
virtio migration 迁移的不是 QEMU 内部实现本身,而是 guest 可见的设备协议状态;只要 queue、feature、config、completion 和 backend 状态一致,guest 才能在 target 上无感继续运行。
15. 下一篇预告:trace、调试与故障定位
下一篇作为本系列收束,讨论如何观察 virtio 路径。
会讨论:
- QEMU trace
- guest dmesg 和 sysfs
- eventfd/ioctl 观察
- vhost 路径确认
- virtqueue 卡死如何定位
- 迁移后设备异常如何排查
下一篇的问题可以写成:
当 virtio 设备不工作或性能异常时,应该从 guest、QEMU、vhost、backend 哪一层开始看?