虚拟机的“外挂神经”:一文搞懂让云主机飞起来的 Virtio 协议
虚拟机的“外挂神经”:一文搞懂让云主机飞起来的 Virtio 协议
在上一篇《虚拟化演进之路》中,我们聊了 VM、KVM 和 MicroVM。我们知道,现代 CPU 很强大,配合硬件虚拟化(Intel VT-x 等),虚拟机执行普通代码的速度几乎和物理机一模一样。
但是,这里有一个巨大的“坑”:I/O 操作(网络和磁盘)。
如果你的虚拟机用的是传统模拟设备(比如模拟的老式 Intel 网卡 e1000 或 IDE 硬盘),你会发现它的网络吞吐量和磁盘 IOPS 惨不忍睹。为什么?因为每一次收发网络包、每一次读写磁盘,虚拟机都要向宿主机“大喊救命”(触发 VM_Exit),让宿主机代劳。这种频繁的上下文切换,直接把 CPU 耗死了。
为了解决这个问题,大牛们发明了一个“作弊神器”——Virtio。
今天,我们就来扒一扒,这个统治了云计算 I/O 性能的核心协议,到底是个什么鬼。
一、Virtio 是什么?不是硬件,是“白皮书”
很多人看到 virtio-net、virtio-blk,会以为这是某种特定的虚拟网卡或虚拟硬盘。
错!Virtio 不是任何实体硬件,它是一套“接口标准”或“通信协议”。
你可以把它理解为虚拟化界的 USB 协议。USB 规定了键盘、鼠标、U盘怎么和电脑通信;而 Virtio 规定了虚拟机里的操作系统,该怎么和虚拟化底层高效地通信。它是一个由 OASIS 国际组织维护的开放标准(目前最新版是 VIRTIO 1.3)。
它的核心哲学只有一句话:既然是假的,就别装真的了。
传统模拟设备(如 e1000 网卡)是让虚拟机“以为”自己插了一张真网卡,然后按照真实的物理芯片协议去驱动它,中间极其繁琐。而 Virtio 则直接告诉虚拟机:“你就是个虚拟机,别走物理协议了,我们用一套专门为虚拟化定制的极简协议直接交流吧!”
二、Virtio 是怎么工作的?前后端架构
Virtio 采用了经典的**“前后端分离”**架构。它把一件事情劈成两半,一半在虚拟机里,一半在宿主机上。
1. 前端:跑在虚拟机里的“顺从司机”
前端就是虚拟机操作系统里的驱动程序(比如 Linux 内核里的 virtio_net 驱动)。
当虚拟机里的应用要发一个网络包时,应用把包丢给内核,内核的 virtio 驱动不会去操作什么硬件寄存器,而是把包打包好,按照 Virtio 协议的格式放倒指定的地方。
2. 后端:跑在宿主机里的“苦力搬运工”
后端是宿主机侧的设备模拟程序(通常是 QEMU 进程,或者是更高效的内核模块 vhost)。
它负责从指定的地方把数据取出来,然后真正地发到物理网络上,或者写入物理磁盘。
3. 传输层:连接前后的“桥梁”
前后端怎么连起来?Virtio 定义了多种“运输工具”(与设备本身是正交解耦的):
- virtio-pci:最常见,伪装成一个 PCI 设备插在虚拟机的 PCI 总线上。
- virtio-mmio:直接映射内存,常用于 ARM 架构或者极简的 MicroVM(如 Firecracker)中,连 PCI 总线都省了。
打个比方:前端是餐厅里的点菜员,后端是厨房里的厨师。传输层就是他们之间传菜的窗口。
三、性能秘籍:Vring(环形缓冲区)与共享内存
光有前后端分工还不够,关键在于他们怎么交接数据。如果点菜员每点一个菜,都要拍一下厨师的肩膀(触发一次 VM_Exit 中断),那性能还是好不了。
Virtio 的杀手锏在于:共享内存 + 环形队列。
在虚拟机启动时,前后端会协商好一块共享内存。这块内存对虚拟机和宿主机同时可见。在这块内存里,Virtio 划出了几个环形缓冲区(叫作 Virtqueue 或 Vring)。
完美的工作流是这样的:
- 批量打包:虚拟机(前端)要把 10 个网络包发出去,它把这 10 个包的内存地址写成“描述符”,一口气扔进 Vring 里。
- 踢一脚:前端通过写一个特定的寄存器,给宿主机发一个信号,这叫 “Kick”(踢门)。
- 批量处理:宿主机(后端)被 Kick 醒,一次性把 Vring 里的 10 个包全部取走,发送到物理网络。
- 异步回调:发完后,后端把处理完的描述符放回 Vring,然后给虚拟机发一个“中断”。虚拟机再回收内存。
发现了吗?在这个过程中,10 个网络包,只发生了 1 次 Kick 和 1 次中断! 数据本身根本不需要拷贝,只是传递了内存地址。这就是 Virtio 能够逼近物理网卡性能的根本原因。
四、Virtio 大家族:你的云主机里都有啥?
如果你在一台阿里云 ECS 或 AWS EC2 上运行 lspci 命令,你会看到满屏的 Virtio 设备。它们各司其职:
- virtio-net:虚拟网卡。你在云主机里看到的弹性网卡(ENI),底层基本都是它。
- virtio-blk:虚拟块设备(硬盘)。高性能云盘通常用它来对接。
- virtio-scsi:更高级的磁盘协议,支持更多的磁盘命令和热插拔,企业级存储常用。
- virtio-gpu:虚拟显卡。现在云桌面(如 AWS WorkSpaces)能看视频甚至轻度打游戏,靠的就是它。
- virtio-balloon:虚拟气球。用来动态调整虚拟机的内存大小(宿主机缺内存时,把虚拟机的内存“吹”走)。
- virtio-serial / virtio-console:虚拟串口。你在云控制台看到的实例“日志输出”和“远程连接终端”,数据就是从这里走的。
- virtio-fs:近几年大火的文件共享协议,专门为容器和 MicroVM 设计,用来把宿主机的目录极高效率地共享给虚拟机。
五、Virtio 的进阶形态:vhost 与 vhost-user
虽然 Virtio 用共享内存解决了数据拷贝问题,但每次“Kick”和“中断”,还是要在用户态(QEMU)和内核态(KVM)之间切换,这依然有开销。
为了榨干最后一点性能,业界推出了 vhost 技术:
- vhost(内核态后端):干脆把 Virtio 的后端从 QEMU(用户态)搬到 Linux 内核里去。这样前后端都在内核里沟通,彻底省去了用户态切换。
vhost-net和vhost-blk是现在的标配。 - vhost-user(用户态后端):随着 DPDK(数据面开发套件)的兴起,人们发现用纯软件在用户态轮询网卡性能更好。
vhost-user允许把后端放到一个独立的用户态进程里(比如 OVS-DPDK 或 SPDK),通过 Unix Socket 和 QEMU 通信。这是目前软路由、SDN 领域的终极性能方案。
六、总结
回到开头的疑问:为什么云主机能这么快?
是因为KVM 解决了“算得快”的问题(CPU/内存虚拟化),而 Virtio 解决了“传得快”的问题(I/O 虚拟化)。
没有 Virtio,现代云计算高昂的虚拟机成本将无法承受;没有 Virtio,MicroVM 也就失去了能在 125 毫秒内启动并处理高并发网络请求的能力。
下次你在 QEMU 启动脚本里看到 -netdev virtio-net-pci,或者在 /dev/ 下看到 vda(virtio disk a)时,你可以会心一笑:哦,就是那个靠“共享内存传纸条”的神器在干活呢。


