Xen 2003 — 让操作系统配合虚拟化,性能直接接近原生
是什么
Xen 是一个虚拟机管理器(hypervisor),让一台物理机同时跑几十个互相隔离的操作系统。日常类比:一栋写字楼的物业——每家租户(操作系统)以为自己独占整层楼,物业(Xen)在背后偷偷分配电梯、空调和保洁。
它的关键创新叫半虚拟化(paravirtualization):改一改客户机操作系统的源码,让它知道自己在虚拟环境里,主动配合 hypervisor。这是和当时主流的全虚拟化(VMware 那种”骗 OS 以为自己在裸机”)截然相反的思路。
代价:必须能改 OS 源码(Linux / BSD 没问题,Windows 早期不行)。 回报:性能损失只有 2%-8%,而当年 VMware 的全虚拟化要损失 30% 以上。
2006 年 AWS EC2 第一代就跑在 Xen 上,撑起了云计算的开局十年。今天即便主流云已经换 hypervisor,virtio、前后端驱动这些设计模式都还在被广泛复用。
为什么重要
不理解 Xen,下面这些事都没法解释:
- 为什么 2006 年的 AWS 能用普通 x86 服务器卖虚拟机,而不是用大型机——是 Xen 把 x86 虚拟化的性能损失从 30% 压到 5% 以下
- 为什么”虚拟化”和”操作系统”这两件事在 2003 年之后开始分家——hypervisor 抢走了一部分 OS 的权力
- 为什么 2017 年 AWS Nitro 又把 hypervisor 拆出去——历史在打转,每一轮都有 Xen 的影子
- 为什么云厂商财报里一直有”虚拟化层”这一项——它从来不是免费的,而且每一代云都在重新分配它的成本
- 为什么 KVM、virtio 这些今天主流的技术里能看到 Xen 的设计痕迹——技术会被替代,但思路被沿用
核心要点
Xen 的设计可以拆成 三件事:
-
改客户机配合 hypervisor:不再让 OS 偷偷执行特权指令(x86 上很多指令在用户态不会报错,只是默默无效),而是让 OS 显式调用
hypercall——就像系统调用,但调到 hypervisor 而不是 kernel。这一步是半虚拟化的精髓。 -
分环(ring)放权力:x86 有 4 个特权环(ring 0-3)。普通系统只用 ring 0(内核)和 ring 3(用户程序),中间两环 30 年没人用。Xen 占 ring 0,客户机内核降到 ring 1,用户程序还在 ring 3。客户机想做特权动作时,必须通过 hypercall 请求 Xen 代办。
-
dom0 管 I/O:第一个被启动的特权域叫 dom0(一个改过的 Linux),它拥有所有真实硬件驱动;其他客户域叫 domU,通过共享内存的”前后端驱动”借道 dom0 访问磁盘和网卡。这样 Xen 自己不用写一堆驱动,复用 Linux 的成熟驱动栈。
三件事加起来:OS 不再假装自己在裸机上,而是承认在 hypervisor 上——于是 hypervisor 不必再用昂贵的指令模拟或二进制翻译来骗它。论文用一句话总结:“协作”比”欺骗”便宜得多。
这种”上下两层重新签契约”的思路在系统设计里反复出现:
- gRPC 让客户端和服务端用同一份 protobuf 描述,省掉了 REST 的解析开销
- io_uring 让 Linux 用户态和内核态通过共享环形缓冲区通信,省掉了 syscall 开销
- WebAssembly 让浏览器和编译器协商一种新中间码,省掉了 JS 解析开销
它们都在做同一件事:当模拟旧接口太贵时,就重新画一条新接口。Xen 是这种思想在虚拟化领域最典型的样本。
实践案例
案例 1:一个特权指令的命运
x86 上 popf(恢复中断标志位)这条指令在用户态执行不会报错,只是默默忽略中断位的修改。这意味着客户机以为自己关了中断,其实没关——状态彻底乱套。
VMware 全虚拟化的解法叫二进制翻译:先扫描客户机代码,把每条 popf 替换成陷阱指令。慢、复杂,且对动态生成代码(JIT、解释器)兼容性不佳。
Xen 的做法:直接改 Linux 源码,把 popf 换成 HYPERVISOR_set_iflag()。一次性改几百处,运行时零开销。代价是必须能拿到 OS 源码——Linux/BSD 没问题,Windows 闭源就不行。
这是个典型的”接口契约”重新协商:与其让 hypervisor 假装硬件、让 OS 继续天真,不如让 OS 知情、主动配合。
案例 2:一次磁盘读的路径
domU(普通客户机)里的应用 read 一个文件:
- 应用 → domU kernel(ring 1)
- domU 的”前端块设备驱动”把请求写入和 dom0 共享的环形缓冲区
- domU 通过
event channel(取代中断)通知 dom0 - dom0 的”后端块驱动”读真实磁盘,把数据放回共享区
- dom0 再发 event channel 通知 domU 完成
这条路径没有任何特权指令模拟,全是协作式调用。所以 I/O 性能也接近原生。
值得注意的是:这套”前后端驱动 + 共享环形缓冲区”模式后来被现代 KVM 直接抄走,叫 virtio。今天每个 Linux 云虚拟机里的 virtio-blk / virtio-net 都能追溯到 Xen 2003 这张图。技术血脉在这里很清晰。
案例 3:内存伸缩——气球驱动
云上一个老问题:物理机内存固定,但每个客户机的需求随业务波动。怎么动态再分配?
Xen 在每个客户机里塞一个气球驱动(balloon driver)。要回收内存时,hypervisor 让某个客户机的气球”膨胀”——气球驱动在客户机内部用正常 API 申请一大块内存,然后告诉 hypervisor”这块物理页我占了但其实不用,你拿走给别人”。hypervisor 就把对应物理页转给需要的客户机。要还回去时气球”放气”,归还内存。
这又是”客户机配合 hypervisor”的具体体现——OS 知道自己在虚拟环境里,主动配合资源调度,而不是被偷偷换页表骗一通。
踩过的坑
-
Windows 跑不了:半虚拟化要求改源码,Windows 闭源。Xen 早期只能跑 Linux/NetBSD/FreeBSD,错过了大量 Windows Server 用户。直到 2005 年 Intel VT-x、AMD-V 出现,Xen 才加了 HVM 模式(用硬件辅助跑全虚拟化),才能装 Windows。但这也意味着 Xen 的”半虚拟化”独门优势开始稀释——别人用硬件辅助一样能做到。
-
dom0 是单点:所有 I/O 必须经过 dom0。dom0 卡住整台机器全卡,dom0 被攻破整台机器全失守。论文当时把 dom0 当成”可信内核延伸”对待,后来安全社区花了多年修补这个面。Xen 4.x 加了”驱动域”机制,允许把磁盘/网络驱动各自跑在独立小域里,缩小爆炸半径。
-
维护两份内核:每改一次主线 Linux 都要重新打 Xen 补丁。这导致主线 Linux 社区长期不愿合并 Xen 补丁。最终 2007 年 KVM(直接利用 VT-x,不改 OS)出现,Linus 选择把 KVM 收进主线。Xen 的半虚拟化路线在通用 Linux 云市场逐步退场——这是”工程协作 cost 也是技术选型”的经典案例。
-
TLB 暴露物理地址:为了性能,Xen 让客户机直接看到机器物理地址(machine address),而不是先一层翻译。代价是迁移虚拟机时要做地址重映射,工程复杂。后来用嵌套页表(EPT / NPT)才解决,但那是硬件演进的功劳,不是 Xen 设计本身。
-
被基准数据反噬:论文里贴了一组 SPEC / OSDB 跑分显示 2-8% 损失,引发轰动。但后来有研究人员复现时发现:某些 I/O 密集 workload 在 dom0 路径上能把损失放大到 30%。论文展示的是好的那一面——这是 systems 论文的常见现象,读者要带着怀疑看 benchmark。
适用 vs 不适用场景
适用:
- 早期云基础设施(AWS EC2 第一代 / Rackspace / 各国云市场早期)
- 嵌入式 / 汽车里的安全分区——Xen 至今活跃在这个领域(车规系统隔离、Qubes OS 桌面安全)
- 教学:理解 hypervisor 设计权衡的最经典材料,14 页论文密度极高
不适用:
- 跑闭源 OS(必须用 HVM 模式 + 硬件辅助,纯半虚拟化做不到)
- 高密度容器场景(Docker / Kubernetes 比 VM 轻一个数量级,启动毫秒级而非秒级)
- 现代公有云大头(AWS Nitro / Google gVisor / Azure 自研 hypervisor 已替代纯 Xen 路线)
- 需要快速热迁移大内存 VM 的场景(page table 重映射太慢,靠后续硬件辅助才解决)
历史小故事(可跳过)
- 1974 年:Popek 和 Goldberg 写下 hypervisor 形式化条件——某些指令必须能”陷入”特权层才有可能虚拟化。当时 x86 还没出生,没人在意。
- 1997 年:Stanford 的 Disco 项目把老 Unix 跑在新硬件上,证明 hypervisor 思路在 RISC 上可行——但 x86 这块硬骨头还没人啃,因为它违反 Popek-Goldberg 条件:17 条特权指令在用户态不报错。
- 1999 年:VMware 发布 Workstation,用二进制翻译硬啃 x86 全虚拟化。性能不算好,但能跑 Windows——这是商业上最重要的事。
- 2003 年 SOSP:剑桥团队发表 Xen 论文,提出半虚拟化绕开 x86 难点。同年 VMware 已商业化(性能差但兼容性好)。两条路线开始竞争。
- 2006 年:AWS 推出 EC2,底层就是 Xen。云计算时代正式开局。
- 2007 年:Citrix 收购 XenSource,同年 KVM 进入 Linux 主线。硬件辅助虚拟化(VT-x / AMD-V)成熟,Xen 的”必须改 OS”独门优势被削弱。
- 2017 年:AWS Nitro 发布,把 hypervisor 大部分功能下沉到专用硬件卡(PCIe 设备),宣告通用云对纯 Xen 路线的告别。
但 Xen 没死——它在车载、嵌入式、安全分区市场仍是主力。论文本身是 hypervisor 设计的标准教科书材料,每个学操作系统的学生都该读一遍。
学到什么
-
接口可以重新画:当现有接口(x86 特权指令)有缺陷时,与其费力模拟,不如改两边的契约。这是一种”放弃透明性换性能”的经典权衡——前提是你能改两边的源码。
-
特权环是工具不是律法:x86 的 4 环架构存在 30 年都没人当主力,操作系统只用 ring 0 和 ring 3。Xen 突然把它用满。好工具往往躺在那里等一个真问题——这条经验值得反复体会。
-
dom0 的妥协:把 I/O 集中给一个特权域,是”性能 + 安全 + 简洁”三选二的现实选择。当时这个决定是正确的(赶时间出货),但后来证明它是 Xen 在安全敏感场景里的脖子。任何”中心化代理”模式都要警惕这个长期代价。
-
硬件演进会埋葬软件创新:VT-x 一出,半虚拟化的核心论点(x86 难虚拟)就过期了。但思路被吸收:现代 KVM 的 virtio 就是 Xen 前后端驱动模型的直接继承。技术不会真的死,只是换名字活下去。
-
“够用就发表”胜过”完美再发表”:Xen 论文里坦承很多限制(不支持 Windows、dom0 单点、迁移复杂),但抓住了”x86 上能跑出 2-8% 损失”这个最关键的事实点就发了。两年后才补漏洞,五年后才有 HVM。这种节奏很值得学习。
延伸阅读
- 论文 PDF:Xen and the Art of Virtualization (SOSP 2003)(14 页,可读性高,新人也能读完)
- 视频:Ian Pratt 2010 LinuxCon Keynote(作者本人讲 Xen 的来龙去脉)
- 对比阅读:VMware ESX Server (OSDI 2002)——Xen 的全虚拟化对手
- 后续工作:KVM: the Linux Virtual Machine Monitor (OLS 2007)——硬件辅助虚拟化怎么改写规则
- disco-1997 —— Stanford Disco,Xen 的精神前辈
- ffs-1984 —— 同样是”改 OS 接口换性能”的经典案例
关联
- disco-1997 —— Disco 是把 hypervisor 思路搬到 RISC 的先驱;Xen 把这条路落到 x86
- lfs-1991 —— 都是系统层”重新设计接口换性能”的范式
- hyperkernel-2017 —— Hyperkernel 用形式化验证证明 hypervisor 安全;和 Xen 论文里的”trust 边界”讨论形成时代对照
- shenango-2019 —— 现代数据中心调度,论文里讨论了 hypervisor 层调度的局限
- ffs-1984 —— 也是”改接口换性能”的经典;FFS 改文件系统布局,Xen 改 OS-硬件契约
反向链接
- arrakis-2014 —— Arrakis 2014 — 让操作系统只管规则、硬件直接服务应用
- denali-2002 —— Denali — 在一台机器上同时跑上千个轻量 VM 的早期实验
- disco-1997 —— Disco — 让没改过的商用 OS 在 64 核大机器上一起跑
- esx-memory-2002 —— ESX Memory 2002 — 让一台机器假装比自己更大的四个魔术
- firecracker-2020 —— Firecracker 2020 — 给 serverless 量身定做的极简 microVM
- haven-2014 —— Haven — 把整个应用装进 CPU 黑盒,让云服务商也看不见
- kocher-spectre-2019 —— Spectre 攻击 — 推测执行偷看别人的内存
- kvm-2007 —— KVM 2007 — 把 Linux 内核本身变成 hypervisor
- lfs-1991 —— LFS 1991 — 把整个磁盘当日志写
- lipp-meltdown-2018 —— Meltdown — 乱序执行偷读内核内存
- mach-vm-1987 —— Mach VM — 把虚拟内存抽象成”对象”,与硬件解耦
- mirage-2013 —— MirageOS Unikernels — 应用即内核,把操作系统编译掉
- shenango-2019 —— Shenango — 每 5 微秒重新分一次核的中央调度器
- soltesz-2007 —— Soltesz 2007 — 容器:比虚拟机轻一档的隔离方案