2. 虚拟化与存储基础
要理解 VirtIO Block 为什么能显著提升虚拟机磁盘性能,必须先回到虚拟化与存储的基础层:CPU 如何被虚拟化、Hypervisor 处在什么位置、Guest 的一次“写磁盘”究竟经过哪些层次。只有把这条路径看清楚,才能明白 VirtIO 到底优化了哪一段。
一、虚拟化原理:把物理资源抽象成可分配的“虚拟资源”
虚拟化的本质是资源抽象与隔离。物理机只有一套 CPU、内存、磁盘和网卡,Hypervisor 通过指令模拟、特权级切换、地址翻译和 I/O 拦截,把这些资源切分成多个互相隔离的虚拟机(VM)。每个 VM 都以为自己独占一套硬件,实际上它的特权指令和敏感操作会被 Hypervisor 截获并代为执行。
以磁盘 I/O 为例,Guest 内核发出一次写请求,通常会经历:Guest 文件系统 → Guest 块层 → 虚拟磁盘驱动 → 触发 VM Exit → Hypervisor 捕获 → 由 Hypervisor 或后端进程访问真实磁盘。这个“陷入—模拟—返回”的过程,就是虚拟化 I/O 开销的主要来源。
二、Hypervisor 类型:Type 1 与 Type 2
Hypervisor(又称 VMM,虚拟机监视器)按运行位置分为两类:
- Type 1(裸金属型):直接运行在物理硬件上,如 KVM(以内核模块形式融入 Linux)、Xen、VMware ESXi。性能好、延迟低,是数据中心主流。
- Type 2(宿主型):运行在宿主操作系统之上,如 VirtualBox、VMware Workstation。部署方便,但多了一层宿主内核,I/O 路径更长。
KVM 常被归为 Type 1,因为它依托 Linux 内核直接管理硬件;但它的设备模拟部分(QEMU)运行在用户态,因此实际是“内核加速 + 用户态设备模型”的混合结构。理解这一点,对后面分析 VirtIO 前后端分离非常关键。
三、全虚拟化与半虚拟化
全虚拟化(Full Virtualization):Guest 不需要修改,Hypervisor 通过二进制翻译或硬件辅助(Intel VT-x、AMD-V)完整模拟硬件。Guest 里的普通驱动(如 IDE、e1000)可直接使用,但每次 I/O 都要陷入模拟,开销大。
半虚拟化(Paravirtualization):Guest 知道自己运行在虚拟机中,使用专门优化的驱动,通过共享内存和通知机制与 Hypervisor 协作,减少陷入次数。VirtIO 就是半虚拟化 I/O 的标准框架:Guest 端是 virtio-blk 前端驱动,Host 端是 QEMU 中的 virtio-blk 后端设备。
| 对比维度 | 全虚拟化 | 半虚拟化(VirtIO) |
|---|---|---|
| Guest 驱动 | 标准硬件驱动 | 专用 virtio 驱动 |
| 是否需改 Guest | 不需要 | 需要安装 virtio 驱动 |
| I/O 路径 | 每次操作触发 VM Exit | 批量描述符 + 通知,减少陷入 |
| 性能 | 较低 | 接近原生 |
| 典型设备 | IDE、e1000 | virtio-blk、virtio-net |
四、块设备与字符设备
Linux 把设备抽象为两类接口:
- 块设备:以固定大小的“块”为单位随机访问,支持缓存和寻址,如 /dev/vda、/dev/sda。磁盘、SSD、virtio-blk 都属于块设备。
- 字符设备:以字节流顺序访问,通常不支持随机寻址,如 /dev/tty、/dev/null。串口、键盘属于字符设备。
这个区分直接决定了 I/O 栈的走向:块设备请求会进入块层,被合并、排序后交给调度器;字符设备则直接走字符驱动。VirtIO Block 作为块设备,其请求同样要经过 Guest 块层的合并与调度,再进入 virtio 队列。
五、I/O 栈分层:一次写请求的完整旅程
下面这张图展示了从 Guest 应用到物理磁盘的分层路径,以及 VirtIO 在其中的位置。可以看到,VirtIO 并没有绕过块层,而是替换了“虚拟磁盘驱动 + 设备模拟”这一段。
从图中可以看出,VirtIO 的优化点集中在“前端驱动 + virtqueue + 后端设备”这一段:Guest 不再模拟真实磁盘寄存器,而是把请求描述符写入共享内存,通过 Avail 环通知 Host;Host 处理完后通过 Used 环回写完成状态。这样把多次 VM Exit 合并为批量通知,显著降低陷入开销。
六、案例与排障:为什么 Guest 里看不到 /dev/vda
一个常见场景是:用 QEMU 启动虚拟机时指定了 -drive if=virtio,但 Guest 启动后只有 /dev/sda,没有 /dev/vda。原因通常是 Guest 内核没有加载 virtio-blk 驱动,或者 initramfs 中缺少该模块。
# 查看 Guest 是否识别到 virtio 设备
lspci | grep -i virtio
lsmod | grep virtio
dmesg | grep -i virtio
# 若缺少驱动,可在 Guest 中加载
modprobe virtio_blk
modprobe virtio_pci
# 检查块设备
lsblk -o NAME,SIZE,TYPE,MOUNTPOINT
七、常见误区复盘
- 误区一:VirtIO 等于直通。 直通(VFIO)是把物理设备直接分配给 Guest,绕过 Hypervisor 模拟;VirtIO 仍是半虚拟化,后端由 QEMU 处理。
- 误区二:块设备和字符设备只是名字不同。 两者在访问方式、缓存策略、是否可寻址上有本质区别,直接影响 I/O 栈走向。
- 误区三:Type 1 一定比 Type 2 快。 性能取决于具体 I/O 路径和加速方式,KVM + VirtIO 的 Type 1 混合结构往往优于纯用户态模拟。
- 误区四:装了 virtio 驱动就万事大吉。 还需关注 virtqueue 大小、多队列、中断亲和性等参数,否则性能仍可能受限。
掌握这些基础后,后续分析 VirtIO Block 的 virtqueue 结构、描述符链和通知机制时,就能清楚每个环节在整条 I/O 路径中的位置与作用。