[Virtualization](十):virtio 与 vhost,虚拟 I/O 如何变快 第九篇讲了 QEMUvirtmachine 和 Device Tree。本篇进入 I/OGuest Linux 看到一个 virtio 设备时一次 I/O 请求究竟如何穿过 driver、virtqueue、QEMU 和 host backend为什么有了 virtio 之后还需要 vhost1. 为什么虚拟设备不能只靠模拟真实硬件最直观的虚拟设备做法是模拟真实设备。例如模拟一块真实网卡或真实磁盘控制器。这种方式兼容性好但有两个问题设备语义复杂每次寄存器访问和中断都可能带来大量 exitvirtio 的思路不同。它不是假装自己是一块传统真实硬件而是定义一套专门面向虚拟化的设备协议。Guest 和 Host 都知道自己在虚拟化环境中于是可以用更直接的共享队列交换请求。2. virtio 的基本分层virtio 可以分成几层看。Guest application | v Guest kernel block/net layer | v virtio-blk / virtio-net driver | v virtqueue | v transport: virtio-mmio or virtio-pci | v QEMU virtio device model | v host backend: file / tap / socket / vhostvirtio driver 和 device model 通过 virtqueue 通信。transport 负责把 virtio 设备暴露给 guest例如 virtio-mmio 或 virtio-pci。backend 负责真正落到 host 资源例如磁盘镜像、tap 网卡或用户态服务。3. virtqueue 是核心virtqueue 是 guest 和 host 交换 I/O 请求的共享队列。可以粗略理解为guest 把请求描述符放进队列host/device model 取走请求并执行host 把完成结果放回队列guest 收到中断或通知后处理完成Guest driver | | add descriptors v virtqueue | | consumed by device model v QEMU / vhost backendvirtqueue 的好处是批量化。相比每次 I/O 都通过复杂寄存器模拟virtqueue 能让 guest 和 host 通过共享内存交换多个请求。4. virtio-mmio 与 virtio-pcivirtio 是设备协议仍然需要一种 transport 暴露给 guest。常见 transportvirtio-mmiovirtio-pci在 RISC-V QEMUvirtmachine 中virtio-mmio 很常见。Guest 通过 device tree 发现 virtio-mmio 设备。在更接近服务器形态的虚拟机中virtio-pci 也很常见。区别可以粗略理解为virtio protocol: 设备如何交换请求 transport: 设备如何被 guest 发现和配置 backend: 请求最终由 host 哪里处理5. virtio-blk 请求路径以 virtio-blk 为例。Guest 读取块设备时大致路径是Guest process reads file | v Guest VFS / block layer | v virtio-blk driver | | submit request descriptors v virtqueue | v QEMU virtio-blk device model | v host image file read | v completion interrupt to guestGuest 看到的是一个块设备。QEMU 看到的是 virtqueue 中的请求。Host 看到的是对镜像文件或块后端的读写。6. virtio-net 请求路径virtio-net 类似但 backend 往往是网络设备、tap、vhost 或用户态网络栈。发送路径Guest TCP/IP stack | v virtio-net driver | v tx virtqueue | v QEMU/vhost backend | v host network接收路径反过来host network receives packet | v QEMU/vhost backend | v rx virtqueue | v Guest virtio-net driver | v Guest TCP/IP stack网络路径对延迟和吞吐都很敏感所以 virtio-net 常常会配合 vhost、multiqueue、offload 等能力。7. QEMU device model 的角色在基础 virtio 模式下QEMU 负责设备模型。它要做解析 virtqueue descriptor执行 host I/O更新 used ring触发 guest interrupt处理设备配置寄存器维护迁移所需的设备状态这说明 QEMU 不只是启动器。即使 CPU 执行交给 KVM很多 I/O 控制面和设备语义仍然在 QEMU。8. 为什么需要 vhostQEMU 用户态处理所有 virtqueue 请求会有开销。尤其是高吞吐网络和块 I/O数据面频繁经过 QEMU 会带来kernel/userspace 切换数据复制或映射开销QEMU 主循环压力中断和通知开销vhost 的目标是把高频数据面从 QEMU 下沉出去。常见形态vhost-kernelvhost-userQEMU 仍然负责控制面例如设备创建、配置、迁移协作。数据面则由更高效的后端处理。9. vhost-kernelvhost-kernel 把 virtqueue 数据面放到 host kernel 中。例如 vhost-net 可以让网络包处理绕开大量 QEMU 用户态路径。简化模型Guest virtio-net driver | v virtqueue shared memory | v vhost kernel backend | v host network stack / tapQEMU 仍然创建设备并把必要的 virtqueue、memory mapping、eventfd 等信息交给 vhost backend。这是一种典型的“QEMU 控制面kernel 数据面”结构。10. vhost-uservhost-user 把数据面交给独立用户态进程。常见于高性能网络例如 DPDK 相关场景。模型QEMU | | vhost-user protocol over Unix socket v vhost-user backend process | v high-performance packet processingvhost-user 的优势是灵活。后端可以独立开发、部署和优化。代价是系统结构更复杂迁移、隔离、故障恢复都需要更谨慎设计。11. notification 与 interruptvirtio 请求不是只靠共享内存。Guest 和 host 还需要通知对方guest 通知 host 有新请求host 通知 guest 请求完成这通常会涉及 kick、eventfd、irqfd、中断注入等机制。Guest submits descriptors | | kick v host backend processes | | interrupt / event v Guest handles completion减少通知次数、批量处理请求是 virtio 性能优化的重要方向。12. virtio 与迁移虚拟设备必须支持迁移。迁移时不仅要复制 guest RAM 和 vCPU state还要保存设备状态。virtio 设备状态可能包括queue indexavailable/used ring 状态device configpending requestsfeature negotiation resultbackend 状态如果使用 vhost迁移还要协调 QEMU 和 vhost backend。这就是为什么 QEMU 控制面不能随便消失。即使数据面下沉设备状态的一致性仍然需要 QEMU 管理。13. 源码阅读入口QEMU/virtio 侧hw/virtio/include/hw/virtio/hw/block/virtio-blk.chw/net/virtio-net.chw/virtio/virtio-mmio.chw/virtio/vhost.chw/virtio/vhost-user.cLinux guest driver 侧drivers/virtio/drivers/block/virtio_blk.cdrivers/net/virtio_net.c阅读问题virtqueue 在 guest 和 QEMU 中分别如何表示descriptor 如何被解析request completion 如何通知 guestvhost 如何接管 virtqueueQEMU 还保留哪些控制面状态迁移时 virtio 设备状态如何保存14. 本篇小结这一篇把 virtio 和 vhost 放在同一条 I/O 路径中看。第一virtio 是专门面向虚拟化的设备协议。第二virtqueue 是 guest driver 和 host device model 交换请求的核心结构。第三QEMU 可以处理完整 virtio device model。第四vhost 把高频数据面下沉到 kernel 或独立用户态后端以降低 QEMU 开销。第五QEMU 仍然负责设备控制面和迁移协作。可以把本篇压缩成一句话virtio 让 Guest 和 Host 用虚拟化友好的队列交换 I/O 请求vhost 则把高频数据面从 QEMU 中拆出去让虚拟设备更接近真实性能。15. 下一篇预告vCPU 调度、timer 与性能治理下一篇把 CPU 时间、timer 和 host scheduler 放在一起看。会讨论vCPU thread 与 host schedulertimer 虚拟化对调度延迟的影响CPU overcommitCPU pinning 与 NUMAhalt/polling/wakeupnoisy neighbor性能观测指标