Linux® 的最重要创新之一就是转变为hypervisor(或运行其他操作系统的操作系统)。现在涌现许多使用 Linux 作为内核的 hypervisor 解决方案。本文探索 hypervisor 背后的原理,以及两个使用 Linux 作为平台的 hypervisor(KVM 和 Lguest)。
hypervisor 之于操作系统类似于操作系统之于进程。它们为执行提供独立的虚拟硬件平台,而虚拟硬件平台反过来又提供对底层机器的虚拟的完整访问。但并不是所有 hypervisor 都是一样的,这是件好事,因为 Linux 就是以灵活性和选择性著称。本文首先简要介绍虚拟化和 hypervisor,然后探索两个基于 Linux 的 hypervisor。
虚拟化和 hypervisor
我们首先花一点时间理解为什么虚拟化很重要,以及 hypervisor 的扮演的角色。(要更多地了解这两个主题,请参见 参考资料)。
在本文中,虚拟化 就是通过某种方式隐藏底层物理硬件的过程,从而让多个操作系统可以透明地使用和共享它。这种架构的另一个更常见的名称是平台虚拟化。在典型的分层架构中,提供平台虚拟化的层称为 hypervisor (有时称为虚拟机管理程序 或 VMM)。来宾操作系统称为虚拟机(VM),因为对这些 VM 而言,硬件是专门针对它们虚拟化的。图 1 简单的展示了这个分层架构。
图 1. 显示常用硬件虚拟化的简单分层架构
平台虚拟化的好处很多。美国环境保护署(EPA)报告的一组有趣的统计数据就证明了其好处。EPA 研究服务器和数据中心的能源效率时发现,实际上服务器只有 5% 的时间是在工作的。在其他时间,服务器都处于 “休眠” 状态。在单个服务器上的虚拟化平台能够改善服务器的利用率,但是减少服务器的数量才是它的最大功用。减少服务器数量意味着减少不动资产、能耗、冷却和管理成本。使用更少的硬件还能提高可靠性。总之,平台虚拟化不仅带来技术优势,还能创造成本和能源优势。
在图 1 中可以看到,hypervisor 是提供底层机器虚拟化的软件层(在某些情况下需要处理器支持)。并不是所有虚拟化解决方案都是一样的,您可以在 参考资料 中了解更多的虚拟化方式。继续讨论进程,操作系统将对机器的底层资源的访问虚拟化为进程。hypervisor 也做一样的事情,但其对象不是进程,而是整个来宾操作系统。
hypervisor 分类
hypervisor 可以划分为两大类。首先是类型 1,这种 hypervisor 是直接运行在物理硬件之上的。其次是类型 2,这种 hypervisor 运行在另一个操作系统(运行在物理硬件之上)中。类型 1 hypervisor 的一个例子是基于内核的虚拟机(KVM —— 它本身是一个基于操作系统的 hypervisor)。类型 2 hypervisor 包括 QEMU 和 WINE。
hypervisor 的构成
hypervisor(不管是什么类型)仅是一个从其来宾操作系统抽象机器硬件的分层应用程序。通过这种方式,每个来宾操作系统看到的仅是一个 VM 而不是真实的硬件机器。我们大致看一下 hypervisor 的内部组成,以及它在 VM(来宾操作系统)上的表示。
在较高级别上,hypervisor 需要少量设施启动来宾操作系统:一个需要驱动的内核映像、一个配置(比如 IP 地址和所需的内存量)、一个磁盘盒一个网络设备。磁盘和网络设备通常映射到机器的物理磁盘和网络设备(如图 2 所示)。最后,需要使用一组来宾操作系统工具启动和管理来宾操作系统。
图 2. 在假设 hypervisor 中的最小资源映射
然后,一个简化的 hypervisor 架构实现最后的关键功能,从而使来宾操作系统可以和宿主操作系统同时运行。实现这个功能需要一些特定的要素,如图 3 所示。首先,类似于将用户空间应用程序和内核函数连接起来的系统调用,一个通常可用的虚拟化调用(hapercall,hypervisor 对操作系统进行的系统调用)层允许来宾系统向宿主操作系统发出请求。可以在内核中虚拟化 I/O,或通过来宾操作系统的代码支持它。故障必须由 hypervisor 亲自处理,从而解决实际的故障,或将虚拟设备故障发送给来宾操作系统。hypervisor 还必须处理在来宾操作系统内部发生的异常。(毕竟,来宾操作系统发生的错误仅会停止该系统,而不会影响 hypervisor 或其他来宾操作系统)。hypervisor 的核心要素之一是页映射器,它将硬件指向特定操作系统(来宾或 hypervisor)的页。最后,需要使用一个高级别的调度器在hypervisor和来宾操作系统之间传输控制。
图 3. 简化的基于 Linux 的hypervisor
Linux hypervisor
本文探索两个基于 Linux 的 hypervisor 解决方案。首先是 KVM,它是首个被集成到 Linux 内核的 hypervisor 解决方案,并且实现了完整的虚拟化。其次是 Lguest,这是一个实验 hypervisor,它通过少量的更改提高准虚拟化。
KVM
KVM 针对运行在 x86 硬件硬件上的、驻留在内核中的虚拟化基础结构。KVM 是第一个成为原生 Linux 内核(2.6.20)的一部分的 hypervisor,它是由 Avi Kivity 开发和维护的,现在归 Red Hat 所有。
这个 hypervisor 提供 x86 虚拟化,同时拥有到 PowerPC® 和 IA64 的通道。另外,KVM 最近还添加了对对称多处理(SMP)主机(和来宾)的支持,并且支持企业级特性,比如活动迁移(允许来宾操作系统在物理服务器之间迁移)。
KVM 是作为内核模块实现的,因此 Linux 只要加载该模块就会成为一个hypervisor。KVM 为支持 hypervisor 指令的硬件平台提供完整的虚拟化(比如 Intel® Virtualization Technology [Intel VT] 或 AMD Virtualization [AMD-V] 产品)。KVM 还支持准虚拟化来宾操作系统,包括 Linux 和 Windows®。
这种技术由两个组件实现。第一个是可加载的 KVM 模块,当在 Linux 内核安装该模块之后,它就可以管理虚拟化硬件,并通过 /proc 文件系统公开其功能(见图 4)。第二个组件用于 PC 平台模拟,它是由修改版 QEMU 提供的。QEMU 作为用户空间进程执行,并且在来宾操作系统请求方面与内核协调。
图 4. KVM hypervisor 的高级别视图
当新的操作系统在 KVM 上启动时(通过一个称为 kvm 的实用程序),它就成为宿主操作系统的一个进程,因此就可以像其他进程一样调度它。但与传统的 Linux 进程不一样,来宾操作系统被 hypervisor 标识为处于 “来宾” 模式(独立于内核和用户模式)。
每个来宾操作系统都是通过 /dev/kvm 设备映射的,它们拥有自己的虚拟地址空间,该空间映射到主机内核的物理地址空间。如前所述,KVM 使用底层硬件的虚拟化支持来提供完整的(原生)虚拟化。I/O 请求通过主机内核映射到在主机上(hypervisor)执行的 QEMU 进程。
KVM 在 Linux 环境中以主机的方式运行,不过只要底层硬件虚拟化支持,它就能够支持大量的来宾操作系统。您可以在 参考资料 部分找一个到受支持的来宾操作系统的列表。
Lguest(以前的 lhype)
Lguest hypervisor 由澳大利亚 IBM 的 Rusty Russell 开发,它采用完全不同的方式实现虚拟化。Lguest 并没有为运行任意操作系统提供完整的虚拟化支持,而是为支持 x86 的 Linux 来宾操作系统(也称为Linux-on-Linux 虚拟化)提供轻量级准虚拟化。这意味着来宾操作系统知道自己正在被虚拟化,并且这同时还会改进性能。但是,Lguest 不需要 QEMU 提供平台虚拟化(像在 KVM 中一样)来改进性能。使用 Lguest 这种方法还减少了总代码需求,仅需在来宾操作系统和宿主操作系统中使用一个瘦层。现在,我们探索这些变化,并查看 Lguest 环境的高级别架构。
如图 5 所示,来宾操作系统包含一个 Lguest 代码瘦层(根据定义,就是准虚拟化)。这段代码提供许多服务。在最高的级别,有一些代码可以决定正在启动的内核是否被虚拟化。此外,还有一个通过虚拟化调用将特权操作发送给宿主操作系统的抽象层(通过 paravirt_ops 实现)。例如,来宾操作系统不能禁用中断,以使这些请求在宿主操作系统中执行。您还可找到一个为来宾操作系统实现设备抽象的总线,以及一组实现控制台、虚拟块驱动器和虚拟网络驱动器(允许与其他来宾通信)的简单驱动器。
图 5. 实现 x86 准虚拟化的 Lguest 的架构
内核部分被实现为可加载的模块,即lg.ko。这个模块包含来宾操作系统通向宿主内核的接口。第一个组件是切换器,它实现一种方法,让来宾操作系统在执行时根据上下文进行切换。这个模块还实现 /proc 文件系统代码(针对 /dev/lguest),该代码实现到内核和驱动器(包括虚拟化调用)的用户空间接口。还有一些代码通过使用影子页表(shadow page-table)和管理 x86 区段来提供内存映射。
最后,内核中的 Documentation 子目录包含启动实用程序(lguest),用于启动新的来宾操作系统实例。这个文件负责两项任务,即使用和记录。
Lguest 从 2.6.23(2007 年 10 月)开始就成为主流内核,并且由 Rusty Russell 开发和维护。它大约包含 5000 行源代码,包括用户空间实用程序。尽管 Lguest 很简单(据说是这样的),但它能提供真正的准虚拟化。不过简单性往往与局限性相随。例如,Lguest 仅虚拟化其他支持 Lguest 的来宾操作系统,并且目前仅能用于 x86 架构。尽管存在这些限制,Lguest 仍然提供一种有趣的虚拟化方式,并且对任何希望研究 Rusty 的代码的人员公开。
Linux hypervisor 的益处
使用 Linux 作为内核开发 hypervisor 有实实在在的好处。最明显的是,以 Linux 为基础开发 hypervisor 受益于稳步前进的 Linux,以及为改进 Linux 投入的大量工作。从典型的优化、bug 修复、调度和内存管理创新到支持不同处理器架构,Linux 都是一个不断进步的平台(引自 Salisbury 市的 John 的 “站在巨人的肩膀上” 一文)。
不久前已经证明,通过向 KVM 添加一个内核模块,就可以将 Linux 内核转变为 hypervisor。Lguest 进一步改进了这种方法,并且通过受限制的准虚拟化进一步简化了该解决方案。