1. 课程导入

在云计算与虚拟化技术体系中,存储始终是最复杂、最容易成为性能瓶颈的一环。CPU 和内存的虚拟化早已成熟,网络虚拟化也借助 VirtIO、vhost、DPDK 等技术走向高性能,而存储虚拟化则因为涉及块设备语义、I/O 栈层次、缓存一致性与持久化保证,长期处于“能跑但难调优”的状态。本课程围绕 VirtIO Block 这一关键组件,系统讲解从虚拟机前端到宿主机后端的完整存储 I/O 路径,帮助你把“虚拟机里的一块盘”拆解成可观测、可分析、可优化的工程对象。

一、存储虚拟化的发展脉络

存储虚拟化并不是一个新概念,它经历了从“模拟”到“半虚拟化”再到“硬件加速”的演进过程。理解这条脉络,有助于我们看清 VirtIO Block 在其中的位置。

  • 全模拟阶段(Full Emulation):早期 QEMU 通过模拟 IDE、SCSI 控制器来为虚拟机提供磁盘。Guest 完全不知道自己在虚拟化环境中,每次 I/O 都要触发 VM-Exit,由 QEMU 逐寄存器模拟,性能开销极大。
  • 半虚拟化阶段(Para-virtualization):VirtIO 规范提出“前端驱动 + 后端设备”的共享内存模型,Guest 使用专用驱动,通过 virtqueue 批量提交 I/O 请求,大幅减少陷入次数。VirtIO Block 正是这一阶段的代表性块设备实现。
  • 硬件加速阶段(vhost / vhost-user / vDPA):把后端处理从 QEMU 用户态下沉到内核态或独立进程,甚至卸载到智能网卡与 DPU,进一步降低延迟、提升吞吐。
  • 云原生存储阶段:在 Kubernetes 场景下,VirtIO Block 后端可能对接本地 NVMe、Ceph RBD、分布式块存储,形成“容器 + 虚拟机 + 分布式存储”的复合栈。

可以看到,VirtIO Block 处于承上启下的核心位置:向上承接 Guest 的块设备语义,向下对接宿主机多种存储后端。

二、VirtIO Block 的定位

VirtIO Block 是 VirtIO 规范中定义的块设备类型,它在 Guest 中表现为一个标准的 /dev/vda 或 /dev/vdb 设备,但底层并不存在真实硬件控制器。其核心机制是:Guest 前端驱动把读写请求放入 virtqueue,后端(QEMU、vhost、vhost-user)取出请求并转发给真实存储,完成后通过中断或事件通知前端。

VirtIO Block 的本质是“用共享内存 + 环形队列替代寄存器模拟”,把一次 I/O 的多次 VM-Exit 压缩为一次批量通知,从而在保持通用性的同时获得接近原生的性能。

它的关键定位可以概括为三点:

  1. 协议层:定义请求头、数据段、状态字节的格式,是前后端通信的契约。
  2. 驱动层:Guest 内核中的 virtio_blk 驱动负责队列管理、请求封装与完成处理。
  3. 设备层:QEMU 的 virtio-blk 设备或 vhost-blk 后端负责请求解析与真实 I/O 下发。

三、整体知识框架与信号链

下图展示了本课程的核心知识框架:从 Guest 应用发起 I/O,到 VirtIO Block 前后端交互,再到宿主机存储后端的完整信号链。后续章节将围绕这条链路逐层展开。

VirtIO Block 存储 I/O 信号链与知识框架 Guest 应用 文件系统 / 数据库 read / write / fsync Guest 块层 bio / request 合并 I/O 调度 virtio_blk 前端 virtqueue 入队 kick 通知后端 VirtIO Block 后端 QEMU / vhost / vhost-user 请求解析与下发 共享内存 virtqueue:Descriptor Table + Available Ring + Used Ring 请求头 | 数据段 | 状态字节 → 批量提交,减少 VM-Exit 宿主机存储后端 本地 NVMe / 文件 / Ceph RBD 性能与可观测性 IOPS / 延迟 / 队列深度 / trace 工程实践 调优 / 排障 / 安全隔离

四、学习目标与典型场景

本课程的学习目标不是让你背诵 VirtIO 规范,而是建立“从请求到落盘”的全链路认知。具体包括:

  • 能说清 VirtIO Block 的请求格式、virtqueue 结构与前后端交互流程;
  • 能读懂 /sys/block/vda/queue/ 下的队列参数并解释其含义;
  • 能使用 fio、blktrace、bpftrace 定位存储 I/O 瓶颈;
  • 能对比 virtio-blk、virtio-scsi、vhost-user-blk 的适用场景;
  • 能识别缓存模式、I/O 调度、队列深度等常见误区。

一个典型场景是:某云主机数据库写入延迟抖动,Guest 内 iostat 显示 %util 接近 100%,但宿主机 NVMe 利用率并不高。问题往往出在 VirtIO Block 的队列深度或后端线程模型上。这类问题只有理解信号链才能快速定位。

五、核心组件对比清单

组件 所在位置 核心职责 常见问题
virtio_blk 驱动 Guest 内核 封装请求、管理 virtqueue 队列深度不足、中断合并
virtqueue 共享内存 前后端请求传递 通知频繁、缓存伪共享
QEMU virtio-blk 用户态 解析请求、调用后端 线程竞争、锁开销
vhost-blk 内核态 绕过 QEMU 处理 I/O 配置复杂、调试困难
存储后端 宿主机/远端 真实数据读写 网络抖动、缓存不一致
学习建议:每学完一个模块,回到上面的信号链图,标出该模块对应的位置。当你能独立画出这条链路并解释每个环节的参数时,VirtIO Block 就不再是黑盒。
常见误区:把 VirtIO Block 当成“纯软件模拟”而忽视其性能模型;或只关注 Guest 内指标,忽略宿主机后端与队列通知机制。存储虚拟化的问题往往跨越多个层次,单点观测容易误判。