3. VirtIO 概述
VirtIO 是 Linux 与 KVM/QEMU 生态中最主流的半虚拟化 I/O 框架。它并不规定某一种具体硬件,而是定义了一套虚拟设备与 Guest 驱动之间的标准接口:Guest 侧安装的是"看起来像真实网卡"的 virtio-net 驱动,Host 侧则由 QEMU 或 vhost 后端实现设备语义。二者通过共享内存中的 virtqueue 交换描述符,从而避免全虚拟化设备频繁陷入模拟的开销。理解 VirtIO,是理解云主机网络性能、vhost-net、vhost-user、DPDK 加速等一系列技术的起点。
一、规范演进:从 0.9 到 1.x 的兼容性分水岭
VirtIO 规范最初由 Rusty Russell 提出,早期以"0.9 版"实现随 Linux 内核与 QEMU 一起演进,长期没有正式标准文本。直到 OASIS 接手后,才形成 VirtIO 1.0(2016 年)及后续 1.1、1.2 等正式规范。这一演进带来两个关键变化:一是设备发现与配置方式标准化,从早期的 PCI 专有寄存器布局,扩展为 PCI、MMIO、Channel I/O 等多种传输层;二是特性位(feature bits)协商机制规范化,Guest 与 Host 必须就可用特性达成一致后才能初始化队列。
工程中最常见的兼容性问题是"legacy 与 modern 混用"。例如老镜像默认走 legacy virtio-pci,而新内核可能优先尝试 modern 设备,若后端未正确暴露特性位,就会出现网卡识别但无法收发报文的现象。排查时应先确认设备类型与协商结果:
# 查看 Guest 内 virtio 网卡与驱动
lspci -nn | grep -i virtio
ethtool -i ens3
# 查看协商到的特性位(Host 侧 QEMU 监控台)
(qemu) info qtree
(qemu) info pci
二、设备与驱动模型:前端、后端与传输层
VirtIO 采用典型的前后端分离模型。Guest 内的前端驱动(virtio-net、virtio-blk 等)负责把上层协议栈的请求封装成描述符;Host 内的后端设备负责消费描述符并完成真实 I/O。二者之间由传输层(virtio-pci、virtio-mmio)提供寄存器与中断通道。三者关系可以用下面的结构图表示。
图中可以看到,Guest 与 Host 并不直接传递数据包,而是通过 virtqueue 中的描述符间接引用 Guest 内存页。这种"零拷贝"设计是 VirtIO 高性能的根本原因,但也意味着内存布局、队列深度、通知抑制等参数会直接影响吞吐与延迟。
三、前后端协作机制:一次收发的完整路径
以 virtio-net 收包为例,一次完整协作大致分为以下步骤:
- Guest 驱动预先在接收队列中填充空缓冲区描述符,写入 Available Ring,并通知 Host。
- Host 后端收到通知后,从 TAP 或物理网卡读取报文,填入对应描述符指向的 Guest 内存。
- Host 将已使用的描述符索引写入 Used Ring,并按需触发中断或事件通知。
- Guest 驱动在中断或轮询中读取 Used Ring,把报文交给协议栈,随后重新填充缓冲区,形成闭环。
发包路径方向相反,但机制一致。关键参数包括队列数量(多队列)、队列深度、中断合并与通知抑制。生产环境中常通过多队列把不同 CPU 的流量分散到不同 virtqueue,减少锁竞争:
# 查看 virtio-net 队列与中断分布
ethtool -l ens3
ethtool -S ens3 | grep -i queue
cat /proc/interrupts | grep virtio
# 调整队列数(需网卡与后端支持)
ethtool -L ens3 combined 4
四、典型应用场景与选型对照
VirtIO 并不只用于网卡。它在云平台中承担了绝大多数半虚拟化 I/O 角色,常见场景包括:
- virtio-net:云主机主网卡,配合 vhost-net 或 vhost-user 提升转发性能。
- virtio-blk / virtio-scsi:云盘与本地盘,virtio-scsi 支持更多队列与热插拔。
- virtio-vsock:Host 与 Guest 之间的高效 socket 通道,常用于监控与日志采集。
- virtio-fs:共享文件系统,替代 9p 以降低元数据开销。
- vDPA / vhost-user:把 VirtIO 数据面卸载到硬件或用户态,兼顾兼容性与性能。
| 后端形态 | 数据面位置 | 典型性能 | 适用场景 |
|---|---|---|---|
| QEMU 用户态 virtio-net | QEMU 进程 | 较低 | 开发调试、低负载 |
| vhost-net | Host 内核 | 中高 | 通用云主机 |
| vhost-user + DPDK | 用户态轮询 | 高 | NFV、高吞吐网关 |
| vDPA 硬件 | 智能网卡 | 很高 | 裸金属云、SR-IOV 替代 |
五、常见误区与复盘要点
复盘时建议按"协商—队列—后端—中断"四层排查:先确认特性位与设备类型是否匹配,再检查 virtqueue 数量与深度,然后确认后端形态与 CPU 绑定,最后观察中断分布与丢包计数。只有把前后端作为一个整体来看,VirtIO 的性能与稳定性问题才能真正定位。