最近,我以前参与过的一款商业化产品 ZSphere,以 ZSvirt 的名字开源了。
我把源代码下载下来,原本只是想随便翻翻。结果从 compute、network、storage 一路看到 kvm、virtio、ceph、vxlan,那些熟悉的名词又冒了出来。
我没有打算重新学习一遍虚拟化,只是看到这些名字以后,忍不住把以前零散的理解重新整理了一次。
这篇文章不准备从缩写讲起。我想先追问一个更原始的问题:我们为什么要虚拟出一台本来不存在的计算机?
01
一、虚拟机先解决的,不是技术问题
想象一套很常见的旧式 IT 环境:OA 一台服务器,门户一台,数据库一台,测试环境再放几台。每套业务都按自己的峰值买机器,平时却很少跑满。
企业级服务器配到十几万元并不稀奇,具体价格会随 CPU、内存、GPU、维保变化,我不把它当成行业均价。但不管采购价是多少,机器只要放进机房,机位、电力、网络和运维成本就已经发生了。
真正浪费的也不是某几个空闲的 CPU 核,而是每套业务都在独占一整套不能自由流动的硬件。
公开数据能帮助我们理解这个量级。美国能源部的公开资料把服务器典型利用率放在 5%—15%;其下属国家可再生能源实验室的一处旧数据中心案例甚至低于 5%。劳伦斯伯克利国家实验室用过一个更直观的例子:原来 5 台服务器各自只用约 10%,整合后可以让 1 台服务器运行在接近 50%。
这里不能偷换成“所有客户都能从 5% 提升到 50%”。业务峰值、冗余要求和性能隔离都会影响结果。这个例子真正说明的是:只要把互相孤立的峰值配置改成共享资源池,同一批工作负载就可能用更少的物理机承载。

虚拟化没有凭空创造算力,它只是重新组织算力:先把物理服务器抽象成 CPU、内存、磁盘和网卡,再按需拼成多台虚拟机。
这次重新组织带来了三件事。
- 共享:不同业务可以错峰使用同一批硬件,提高整体利用率。
- 隔离:每个业务仍然拥有自己的操作系统、进程和地址空间。
- 可移动:一台“服务器”从具体硬件变成一组可创建、快照、迁移和回收的资源。
所以虚拟机的价值从来不只是“在一台机器里再装几套系统”,而是把硬件变成一种可以分配、回收和治理的产品资源。
02
二、从一台虚拟机,长成一套云平台
单机虚拟化解决了“怎样切一台服务器”,但客户很快会问下一组问题:有几百台服务器怎么办?谁来选择宿主机?网络如何隔离?磁盘从哪里创建?一台宿主机坏了,虚拟机怎样恢复?
云平台就是沿着这些问题向上长出来的。也因此,KVM、OpenStack、阿里云的飞天和 VMware 经常一起出现,却不是同一种东西。

从产品视角看,云平台与 Hypervisor 的差别就在这里:Hypervisor 负责把一台虚拟机运行起来,云平台还要把身份、配额、调度、网络和存储组织成一次完整交付。

图里的“编排事务”很关键。用户点击一次创建,平台需要同时预留计算容量、IP、网络策略和云盘;其中任何一步失败,还要把前面已经占用的资源归还。后面看到的 KVM、OVS 和 Ceph,分别处在这张图更靠下的数据面。
KVM 在 2007 年进入 Linux 主线以后,逐渐成为 Linux 生态最重要的虚拟化底座之一。OpenStack Nova 的官方文档也写得很克制:多数部署使用 libvirt/KVM,但 Nova 还支持其他计算驱动比如 XEN。阿里云的飞天(虽然最开始也是基于 KVM 二开)则站在更高一层,它不是 KVM 的另一个名字,也不等于 OpenStack,而是阿里云用来组织大规模数据中心资源的分布式云操作系统。
因此,说“现在所有云都是 KVM”并不准确。更准确的说法是:KVM 奠定了现代 Linux 虚拟化的一套主流实现,OpenStack、ZSvirt 这类平台在它之上把计算、存储和网络做成产品;飞天则代表了阿里云面向更大规模构建云操作系统的路径。
在 AI 时代之前,这些平台主要承载网站、办公系统、ERP、中间件、数据库、开发测试和行业应用。至少在我过去接触的产品语境里,私有云很重要的一类客户来自泛政府领域,也包括国企、教育、医疗等对数据位置、采购方式、合规和本地运维有明确要求的组织。
AI 到来以后,虚拟机没有消失,变化的是稀缺资源。过去最常看的指标是 vCPU、内存和云盘;现在还要看 GPU、显存、PCIe 与 NUMA 拓扑、高速互联和持续供数。平台也不再只交付“一台长期存在的机器”,还要让一次训练或推理任务按时完成。
这会让虚拟机、容器、GPU 直通、vGPU 和裸金属长期共存。通用业务需要隔离、迁移和资源池化,大规模训练更愿意缩短路径、独占设备。AI 改变的是取舍的重心,并没有改掉云平台最基本的三个问题:
算力在哪里执行?数据存在哪里?数据怎样流动?
接下来不再继续铺行业背景,而是顺着一台虚拟机,分别拆开计算、网络和存储。在这之前,要先看懂 KVM 这套体系为什么一直在缩短 I/O 路径。
03
三、KVM 的演进:CPU 交给硬件,I/O 不断少绕路
KVM 在 2006 年公开,随后进入 2007 年发布的 Linux 2.6.20 主线。它做对了一个关键选择:不重新发明一套完整的操作系统,而是让 Linux 内核具备 Hypervisor 能力。
这里先把 Hypervisor 讲清楚。它不是某个固定产品的名字,而是一种角色:负责让多台虚拟机共享物理硬件,同时隔离各自的 CPU、内存和设备访问。VMware ESXi 是一套完整的 Hypervisor;在 Linux 这套体系里,KVM 承担的是内核里最关键的执行部分。
Intel VT-x、AMD-V 等硬件辅助虚拟化技术,让大部分 Guest 指令可以直接在物理 CPU 上执行;KVM 处理虚拟 CPU 和内存,Linux 原有的调度、内存管理和设备驱动则继续复用。
但只有 KVM 还组成不了一台完整的虚拟机。操作系统除了 CPU 和内存,还要看到主板、时钟、磁盘和网卡,这就是 QEMU 出现的位置。
QEMU 原本是一套机器模拟器和虚拟化程序。它既能用软件模拟 CPU,也能模拟一整套计算机设备。在云平台最常见的 QEMU/KVM 组合里,QEMU 不再逐条翻译普通 CPU 指令,而是打开 KVM 提供的接口,把指令执行交给 KVM 和硬件;自己保留一个虚拟机进程,负责内存映射、vCPU 线程、设备模型和启动参数。讲人话就是:KVM 让虚拟机跑得动,QEMU 把它组装成一台完整的电脑。
libvirt 又在它们上面一层。云平台通常不会为每台虚拟机手工拼一长串 QEMU 命令,而是把 CPU、内存、磁盘、网卡等配置交给 libvirt。libvirt 再管理 QEMU 进程,完成创建、启动、停止和迁移。它主要处在管理路径上,通常不参与每一个网络包或磁盘块的高频搬运。
把三者压缩成一条调用链,就是:
云平台 → libvirt 管理生命周期 → QEMU 创建虚拟机和设备 → KVM 执行 Guest 指令 → 物理 CPU。
而当虚拟机开始收包、发包和写盘时,数据还可能从 QEMU 分流给 Virtio、vhost 或硬件直通。下面这张图把管理路径、CPU 路径和设备路径放在了一起。

图中有一条容易忽略的边界:libvirt 管理虚拟机生命周期,QEMU 承载虚拟机进程和设备模型,但高频数据不一定继续由 QEMU 搬运。Virtio、vhost、vhost-user、SR-IOV 和 vDPA 的出现,都是在重新安排数据面。
这不是新组件逐个淘汰旧组件的版本史。先把七种架构放进同一套分层坐标里:Guest 在上,硬件在下;青色实线是高频数据路径,灰色虚线是创建、配置与控制路径。读图时只需要追问一件事:这一代架构,究竟是谁在搬运高频数据?

图中最重要的不是时间,而是琥珀色方框的位置:数据面消费者从 QEMU 用户态,移到宿主机内核、专用用户态后端,最后进入硬件。QEMU 在 vhost 之后依然存在,只是从高频数据面退回了创建、配置和控制路径。
QEMU 设备模拟:所有 I/O 先经过用户态中转
最初还没有 Virtio。QEMU 模拟真实网卡或磁盘控制器,Guest 继续使用已有驱动;兼容性很好,但寄存器、状态和中断都要由软件重现。

QEMU 是宿主机上的用户态进程。它完成设备模拟后,仍要请求 Linux 内核驱动真实设备。高频路径既有 Guest 到 QEMU 的 VM Exit,也有 QEMU 到 Host Kernel 的系统调用。QEMU 像一个功能完整的中转站,但吞吐量越高,切换和 CPU 开销越明显。
Virtio + QEMU:先把设备接口标准化
Virtio 先改变 Guest 看设备的方式:既然双方都知道这是虚拟机,就不再假装面前是一块真实设备。Virtio 驱动把数据描述符放进 Virtqueue,后端从共享队列取走任务。

这一步省掉了大量传统设备模拟,但如果 Virtqueue 的后端仍是 QEMU,那么高频 I/O 还是要经过 QEMU 用户态,再进入 Host Kernel。换句话说,Virtio 先稳定了前端接口,尚未完全解决谁来搬数据的问题。
vhost-net:把网络数据面移进内核
接下来出现了一个很自然的问题:QEMU 收到网络包以后,最终还是要交给 Linux Kernel,那么数据面能不能直接放进内核?这就是 vhost 的出发点。

引入 vhost-net 后,QEMU 依然负责创建虚拟机、配置 Virtio 设备和管理生命周期;但 Virtqueue 中的网络数据由内核里的 vhost-net 直接消费,再进入 TAP、网络协议栈和网卡驱动。变化的关键不是 QEMU 消失了,而是 QEMU 从高频 I/O 数据路径中被移走了。
vhost-user:把数据交给专用用户态后端
把数据面放进内核并不是终点。OVS-DPDK、SPDK 等后端可以通过 vhost-user 直接消费 Virtqueue,配合轮询、DMA 和用户态驱动绕开通用内核协议栈。

这里看起来又“回到用户态”,其实角色已经变了:高频数据不再交给通用的 QEMU 设备模型,而是进入专门为数据面优化的进程。它能减少通用路径中的切换和复制,但轮询往往需要独占 CPU,部署、故障定位和运维也更复杂。
SR-IOV、vDPA 与 DPU:继续把数据面推向硬件
继续下沉,软件只保留控制和策略:SR-IOV 把硬件虚拟功能分配给 Guest;vDPA 保留 Virtio 接口,让硬件承担后端数据面;SmartNIC 和 DPU 还能承接交换、存储和安全卸载。

路径更短、Host CPU 占用更少,但代价不会消失,只会换位置:设备能力差异、平台兼容、可观测性和热迁移都会变得更难处理。
路径越短,通常意味着更少的 VM Exit、上下文切换和数据复制,但代价也会转移:轮询需要专用 CPU,设备直通会增加热迁移和可观测性的难度,硬件卸载还会带来设备能力与平台兼容问题。
因此,总览图中没有写一个看似精确的“提升 3 倍”或“达到 100 Gbps”。这类结果只有在网卡或 NVMe 型号、包或块大小、队列数、CPU 绑核、NUMA、Huge Page 等条件一致时才可比较。对产品经理更有用的性能参数,是一条路径经过多少层、产生多少次切换、占用多少 Host CPU,以及它是否还支持迁移和完整的软件网络能力。
在 ZSvirt 的代码里,我也看到了 Virtio、virtio-scsi、SR-IOV、vhost-user 和 vDPA 等分支。它们并不是重复建设,而是在兼容性、性能、功能和可运维性之间保留不同答案。
有了这张总图,就可以把计算、网络和存储分别拆开。
04
四、计算虚拟化:指令已经很快,调度仍然有代价
计算虚拟化首先要回答:一颗虚拟 CPU,最后到底在哪里运行?
在 QEMU/KVM 中,一颗 vCPU 通常对应宿主机上的一个线程。Guest 的普通指令借助硬件辅助虚拟化直接在物理 CPU 上执行;遇到需要 Host 介入的事件时发生 VM Exit,交给 KVM 或 QEMU 处理。与此同时,Linux 调度器还要决定这个 vCPU 线程何时运行、落在哪颗 pCPU 上。

这解释了为什么今天的 CPU 虚拟化损耗通常很低,却不能简单写成“零损耗”。成本主要藏在下面几处:
- 二次调度:Guest 里有一次线程调度,Host 还要再调度 vCPU 线程;CPU 超分时会产生等待和抖动。
- VM Exit:特权操作、中断或部分设备访问需要退出 Guest,再进入 Host 处理。
- NUMA 距离:vCPU 在一个 NUMA 节点运行,却访问另一个节点的内存或设备,延迟会明显增加。
- 共享争用:缓存、内存带宽和 I/O 通道仍然由多台虚拟机共享。
所以计算产品会提供 CPU 绑核、NUMA 亲和、Huge Page、独占宿主机和 CPU 模型等能力。OpenStack 的 KVM 文档明确指出,host-passthrough 可以暴露宿主机 CPU 的完整能力、获得更好的性能,但也会限制虚拟机在不同 CPU 型号宿主机之间迁移。
沿着“只追求单机性能”这条轴继续走,计算虚拟化的终点确实是裸金属:没有 Host 再调度一遍 vCPU,也不必隐藏部分 CPU 特性。但云产品还有隔离粒度、弹性、热迁移和资源利用率这些目标,所以裸金属不是虚拟机的下一代,而是这组取舍中性能最靠前的端点。
CPU 指令路径看清以后,真正复杂的部分才开始。虚拟机每一次收包、发包和写盘,都要跨过 Guest 与 Host 的边界。
05
五、网络虚拟化:一只数据包经过了谁
网络名词很多,但沿着一只数据包往下追,只需要连续问三个问题。

1. VM 看见什么网卡?
Guest 操作系统必须先看到一张网卡。QEMU 可以模拟传统网卡,优点是老系统通常已有驱动,缺点是 Host 要付出完整设备模拟的成本。virtio-net 则承认双方都处在虚拟化环境中,让 Guest 驱动通过 Virtqueue 与 Host 交换数据。
这一步决定的是兼容性边界:老系统是否能启动,镜像里是否装了 Virtio 驱动。
2. Virtqueue 由谁消费?
数据进入 Virtqueue 以后,可以由 QEMU 处理,也可以交给内核中的 vhost-net;如果使用 vhost-user,还可以交给 OVS-DPDK 等用户态数据面。
这一步决定的是软件路径:包要不要经过 QEMU,要发生多少次上下文切换,需要多少 Host CPU。DPDK 常用轮询和批处理减少中断、提高吞吐,但它是在用专用 CPU 换性能,并不是免费的加速按钮。
3. 包离开 VM 后去哪里?
同一宿主机内,Linux Bridge 或 OVS 可以完成二层转发;跨宿主机时,VXLAN 等 Overlay 会把租户数据包再封装一层,穿过物理网络送到目标主机。安全组、ACL、QoS、NAT 和路由也大多发生在这一段。
这一步决定的是云网络能力:多租户怎样隔离,地址如何管理,策略在哪里生效,出了丢包能否看见完整链路。
如果这些软件路径仍然不够快,SR-IOV 可以把物理网卡划分出 Virtual Function,再通过 VFIO 分配给虚拟机;vDPA 则让硬件或软件数据面遵循 Virtio 接口。它们可以把性能推向近原生,但虚拟机与设备的绑定会更紧,热迁移、故障切换、策略能力和可观测性都要重新设计。
把同宿主机、跨宿主机和硬件直通放在一起看,网络方案的取舍会直观很多。

同宿主机通信不必经过物理网卡;跨宿主机要增加 Overlay 封装和物理网络;SR-IOV 则缩短 Host 软件路径。路径越短不等于方案越好,安全组、迁移、故障切换和可观测性同样属于产品能力。
所以网络虚拟化没有唯一的“最先进方案”。virtio-net + vhost-net + OVS 更容易获得完整云网络能力;vhost-user 适合愿意用 CPU 换高吞吐的场景;SR-IOV 适合更在意时延和性能的工作负载。产品要做的不是追逐名词,而是在兼容、功能、性能和可运维性之间选路径。
网络解决了数据怎样流动,最后还剩下更不能出错的一件事:数据怎样留下来。
06
六、存储虚拟化:写下去的数据,最后落在哪里
网络处理 Packet,存储处理 Block I/O。理解方式几乎一样,仍然沿着一条请求问三次。

1. VM 看见什么磁盘?
Guest 里的 /dev/vda 不一定对应一块真实硬盘。它可能是宿主机上的 raw 或 qcow2 文件、LVM 逻辑卷、Ceph RBD 镜像,也可能来自共享块存储。
传统 IDE、SATA、SCSI 设备优先兼容;virtio-blk 和 virtio-scsi 则通过 Virtqueue 缩短虚拟化路径。virtio-blk 更直接,virtio-scsi 更适合多磁盘和更完整的 SCSI 能力。
2. 这次 I/O 由谁处理?
一次写盘会从应用进入 Guest 文件系统和块层,再通过虚拟磁盘到达 Host。后端可以由 QEMU 处理,也可以通过 vhost-user 交给 SPDK 等专门的数据面。
SPDK 采用用户态驱动、轮询和异步 I/O,减少系统调用、中断与上下文切换。它可以换来更低、更稳定的延迟,但通常要预留 CPU 核心,并接受更复杂的部署、监控和故障排查。
3. 数据最终落在哪里?
本地盘路径短、性能直接,但宿主机故障会影响数据与迁移;SAN、NAS 和共享块存储便于集中管理,却依赖存储网络和专用设备;Ceph RBD 通过分布式副本和横向扩容适配云平台,代价是更长的软件链路和更高的运维复杂度;NVMe-oF 试图通过网络提供接近本地 NVMe 的访问方式,对网络、硬件和调优要求也更高。
这一步才真正决定可靠性。快照、备份、副本、故障域和一致性策略,都不能由 Guest 里那块看似普通的磁盘单独回答。
以 Ceph RBD 为例,虚拟机看到的仍是一块盘,但写请求进入 Host 后,会根据集群映射找到目标 OSD,再由存储池策略决定副本或纠删码数据如何分布。

图里特意把 MON 放在管理路径:它提供集群状态和 OSD 映射,但不会搬运每一次块 I/O。真正的数据由客户端直接写向 OSD;满足存储池的写入策略后才返回结果。更长的链路不是白绕,它换来的是单盘或单节点故障后,数据仍然有机会恢复。
ZSvirt 同时支持本地存储、NFS、Ceph、共享块和外部存储插件,正是因为业务目标不同。数据库更在意稳定延迟,通用虚拟机更看重快照和迁移,低成本场景可能接受本地盘,AI 训练还要追问数据集读取和检查点写入的吞吐。
存储虚拟化最终平衡的是性能、可靠性和可移动性。每多一份副本、每跨一次网络、每增加一层抽象,都会付出容量、时延或复杂度;平台用这些成本换来故障恢复和资源流动。
07
七、再回到那个“创建虚拟机”按钮
现在再看 ZSvirt 的创建虚拟机流程,顺序就不难理解了。
平台先确定镜像,再为 vCPU 和内存选择宿主机,为云盘找到主存储,为网卡分配二层网络、IP 和安全策略,最后才调用 Hypervisor 真正创建虚拟机。任何一步失败,前面已经占用的容量、云盘和 IP 还要按顺序归还。
界面上的一个按钮,后台其实在完成一次跨计算、存储和网络的资源事务。
这也是我重新翻这些代码以后最大的感受。云计算并没有把服务器变得神秘,它只是把一台物理计算机拆开,重新组织,再用产品把复杂性收回平台内部。
下一次再看到 KVM、Virtio、vhost、OVS、Ceph、SR-IOV 或裸金属时,只要先把它放回这四个问题里:
为什么要共享这批硬件?算力在哪里执行?数据由谁搬运?数据最终落在哪里?
这几个问题能回答清楚,虚拟化就不再是一堆散落的名词,而是一套围绕资源效率、隔离和性能不断做取舍的产品系统。

夜雨聆风