KVM 的十年(2016)

KVM 于 2006 年 10 月 19 日被它的缔造者 Avi Kivity 首次发布在 Linux 内核邮件列表的这个提交中。

第一版的 KVM 补丁支持VMX 指令集,这个指令集刚被 Intel 公布不久。紧接着又支持了 AMD 的SVM 指令集。这个补丁在 2006 年 12 月合并进了上游的内核中,在次年的 2 月随着 2.6.20 版本内核一起发布。

背景

在没有新的虚拟化扩展的支持下,在 x86 架构上运行多个 guest 操作系统是比较困难的:

  • 有些指令只能够在最高特权级(ring0)运行,无法在不影响其他操作系统的前提下,将这种操作权限开放给每个操作系统;
  • 此外,有些指令在较低权限级别执行时不会产生 trap,尽管他们需要更高的特权级才能正确地工作。因此,在更低特权级上运行 guest 操作系统,然后 ring0 上运行一个hypervisor也不是一个解决方法;

VMX 和 SVM 指令在 x86 架构上引进了一种新的 ring,ring1。这是 VMM 或者 hypervisor 运行的特权级。这个 VMM 为各种操作系统对硬件的访问进行仲裁,以便它们可以在常规的 x86 环境中继续正常运行。

在一个硬件系统上运行多个 guest 系统有很多理由:

  • 通过虚拟机管理工具可以很方便地部署和管理多个 guest 系统;
  • 通过在更新、功能更强的硬件上托管多个操作系统及其相应的应用程序和服务,它还可以降低能耗和冷却成本;
  • 通过虚拟机监控程序模拟旧硬件,在较新的硬件上运行老的操作系统和应用程序,而无需进行任何更改来适应较新的硬件;

在引入 KVM 的时候,Xen 是事实上的开源 hypervisor。由于 Xen 是在 x86 上提供虚拟化扩展(VT-X/AMD-V)之前引入的,所以它使用了不同的设计。

  • 首先,他需要运行一个经过修改的 guest 内核;
  • 其次,Xen 接管了 host 内核的角色,将 Linux 降级为仅作为 Xen 特殊的“Dom0”虚拟机的一部分来管理 I/O 设备 这意味着该系统不能真正地被称为 Linux 系统——甚至客户操作系统都是用 (当时) 非上游代码修改过的 Linux 内核。

Kivity 是在以色列初创公司 Qumranet 工作时开始开发 KVM 的,当时他的工作是修复公司正在进行的与 Xen 相关的工作中。最初的 Qumranet 产品想法是在两个不同的 vm 之间复制机器状态,以实现容错。Qumranet 的工程师们很快就意识到,Xen 的局限性太大,其模型也不适合他们的需求。当时虚拟化扩展正被引入到 AMD 和 Intel 的 cpu 中,因此 Kivity 启动了一个基于新的硬件虚拟化规范的编外项目——KVM,它将被用作容错解决方案的管理程序。

开发模型

从一开始,Kivity 编写代码时就考虑到了将它与上游保持一直。KVM 模型的目标之一是尽可能多地重用现有功能:利用 Linux 完成绝大多数工作,KVM 只作为一个驱动程序,处理由硬件暴露的新的虚拟化指令。这使得 KVM 可以获取所有 Linux 开发者提供给系统的新的特性,例如增强 CPU 调度,内存管理,电源管理等等;

这种模式也适用于 Linux 生态系统的其他部分。最初只是考虑虚拟化而设计的特性在一般的用例中同样变得有用且被广泛采用。例如 [[transparent hug pages 透明大页]]。操作系统和 VMM 没有分割成两个独立的社群,大家在同一个项目中工作。

由于 VM 能够被当作一个常规的进程进行监控,对 VM 的管理也变得简单很多。现在,perf 可用于监视 host 上的 guest 活动并识别性能瓶颈,进一步的芯片组改进还将允许从 host 测量 guest 进程性能。

KVM 的另一面在用户空间,用来提供给 guest 操作系统的机器就是在这里构建的。kvm-userspace就是从 [[QEMU]] 项目 fork 来的。QEMU 是一个机器模拟器——它可以为它支持的各种体系结构运行未经修改的 OS 映像,并为它所运行的主机体系结构模拟那些体系结构的指令。这当然是非常慢的,但是 QEMU 项目的优点是它已经为 x86 体系结构模拟了很多设备——比如芯片组、网卡、显示适配器等等。

kvm-userspace减少了仿真部分的代码,只允许 x86-on-x86 以及使用 [[Using the KVM API KVM API]] 作为 hostCPU 上真正运行 guest 系统。当 guest 系统执行一个特权操作,CPU 将退出到 VMM 的代码。接着 KVM 会接管,如果 KVM 能够自己为这个请求提供服务,那么它就会提供服务,并将控制权交还给 guest 系统。这是一个lightweight exit。如果 KVM 无法服务这个操作,例如设备模拟,它就会退出到 QEMU。这意味着要从主机 Linux 内核退出到用户空间,因此这被称为heavyweight exit

该模型的一个缺点是需要维护 QEMU 的分支。早期的开发人员将重心放在使内核模块稳定上,同时让越来越多的 guest 顺畅无阻地运行。这意味着花费在设备模拟上的时间就少了,因此,为使这些代码适合上游用户而重新编写这些代码的工作仍然处于较低的优先级。

Xen 的 HVM 模式(使用硬件虚拟化指令的模式)同样从 QEMU 上 fork 了设备模拟相关的代码。此外,QEMU 对于 x86-on-x86 有自己的非上游 Linux 内核加速模块 (KQEMU),它消除了仿真层,使得 x86 客户机在 x86 的硬件上运行的更快。要集成所有这些东西,需要一个能够理解所有项目的各种需求的维护者。Anthony Liguori 成为了 QEMU 项目的维护者,并且得到了 Xen 和 KVM 社区的信任。随着时间的推移,分支被消除了,现在 KVM 和 Xen 使用上游的 QEMU 进行它们的设备模型仿真。

do one thing, do it right以及everything is a file的理念在 KVM 中充分体现。KVM API 允许在 Linux 系统上创建 vm——或者沙盒。它们可以在内部运行操作系统,或者运行任何不会干扰运行系统的代码。这也意味着还有其他一些不像 QEMU 那么重量级或功能强大的用户空间的实现。可以通过 KVM VM 快速引导到小型应用程序或专用操作系统的工具开始出现——其中最流行的工具就是 [[kvmtool]]。

开发者感兴趣的

自从 KVM 项目最初发布以来,许多黑客都开始对 KVM 感兴趣。对 KVM 的入侵非常方便:安装新的 VMM 不需要重新启动系统。只需重新编译 KVM 模块、删除旧模块并加载新编译的模块即可。这在早期的稳定和改进阶段非常有帮助。与编译新的 VMM、安装它、更新引导加载程序并重新引导系统相比,调试过程要快得多,开发人员更喜欢这种工作方式。另一个优点是,运行虚拟机不需要 root 权限,这在开发系统上可能不太重要,但对于我的工作 - 开发笔记本电脑却是必不可少的。

KVM 模块和 QEMU 分离带来的另一个方便的调试技巧是,如果某些东西在 KVM 模式下不能工作,但在模拟模式下工作,那么故障很可能出现在 KVM 模块中。如果某些来宾操作系统在这两种模式中都不能工作,则故障在设备模型或 QEMU 中。

早期的 KVM 发布模型也帮助我们获得了轻松的开发体验:即使 KVM 项目是上游 Linux 内核的一部分,Kivity 还是在单独的发布系列中维护 KVM 代码。定期发布新的 KVM 版本中包括 KVM 模块的源代码、用于在任何受支持的 Linux 内核上编译 KVM 模块的小兼容层,以及 KVM-userspace 部分。这确保了发行版内核 (拥有 KVM 模块的旧版本) 可以通过编译来自该内核的最新 KVM 版本的模块而不加修改地使用。

兼容性层需要进行一些维护。它需要通过模拟新的 API 来确保使用在旧内核上没有的新内核 API 的新的 KVM 代码能够继续工作。添加这样的 API 兼容性函数是一次性的开销,但是对于新的贡献者来说,进入的障碍大大降低了。黑客可以下载最新的 KVM 版本,根据正在运行的内核编译模块,然后看到虚拟机启动。如果这不能运行,那么开发人员可以发布错误修复补丁。

被广泛地采纳

芯片供应商开始感兴趣并将 KVM 移植到他们的架构中:

  • 英特尔增加了对 IA64 的支持以及对 x86 的特性和稳定性修复;
  • IBM 增加了对 s390 和 POWER 架构的支持;
  • ARM 和 Linaro 贡献了 [[ARM port]];
  • Imagination Technologies 增加了 MIPS 的支持。

开发人员的兴趣也可以在 KVM 论坛上看到,这是对 KVM 虚拟化感兴趣的人的年度聚会。在 2007 年的第一个 KVM 论坛上,有一些开发人员在一个房间里进行了许多关于当前事态和未来走向的讨论。由 Rusty Russell 领导的一个小组占据了白板,并开始讨论 KVM 的半虚拟化接口应该是什么样子。这就是 [[VIRTIO]] 开始成形的地方。如今,KVM 论坛是一个完整的会议,有并行的轨道、数十位发言者和数百名与会者。

随着时间的推移,很明显 KVM 内核模块并不是最活跃的—指令模拟或多或少已经完成,而且大多数发行版都提供了最新的 Linux 内核。焦点转移到了用户空间:添加更多的设备模拟,使现有设备性能更好,等等。然后 KVM 版本开始更多地关注用户空间部分,并且简化了兼容层的维护。此时,即使存在 kvm-userspace 分支,也要努力确保新特性进入 QEMU 项目,而不是 kvm-userspace 项目。Kivity 也开始提供从 kvm-userspace 存储库到 QEMU 项目的小更改。

当这一切发生的时候,Qumranet 改变了方向,现在正在追求使用 KVM 作为管理程序的桌面虚拟化。2008 年 9 月,红帽公司宣布将收购 Qumranet。自从 Red Hat Enterprise Linux 5.0 发行版以来,Red Hat 就支持 Xen 虚拟机监控程序作为其官方 VMM。在 RHEL 5.4 发行版中,Red Hat 开始同时支持 Xen 和 KVM 作为管理程序。随着 RHEL 6.0 的发布,Red Hat 只支持 KVM。KVM 在其他发行版中也继续享受开箱即用的支持。

现在和未来

现在有许多项目使用 KVM 作为默认的 hypervisor:OpenStack、oVirt 和 ZStack 等等。这些项目关注的是 KVM 主机和多个 vm 在一个部署中的大规模部署。它们带有很多不同的用例,因此对 KVM 有许多不同的述求。随着客户操作系统越来越大 (RAM 和虚拟 cpu 越来越多),在不产生长时间停机的情况下热迁移变得越来越困难;电信公司的部署需要低延迟的网络数据包处理;因此 [[realtime KVM]] 是一个值得关注的领域;更快的磁盘和网络 I/O 一直是一个研究领域。此外,还在努力保持一切安全并减少虚拟机监控程序的占用空间。恶意来宾机如何突破其 VM 沙箱以及如何减轻此类攻击也是主要关注的领域。

新的硬件更新和设备带来了很多进步。然而,许多工作也花费在优化当前的代码基础、编写新算法和提出新的方法来提高现有基础设施的性能和可伸缩性上。

在未来的十年,讨论的主要主题可能不是关于虚拟机监控程序的开发。更有趣的是了解如何将 Linux 用作虚拟机监控程序,为运行不受信任的代码 (尤其是在移动电话上) 和运行云基础设施提供更好的沙盒,使其既普及又不可见。