第4章 面向计算资源共享最大化和管理自动化的软件定义计算

4.1 XEN/KVM虚拟化引擎

4.1.1 虚拟化架构分类

计算虚拟化技术的实现形式是在系统中加入一个虚拟化层,将下层的资源抽象成另一种形式的资源,供上层使用。

计算虚拟化技术的通用实现方案是将软件和硬件相互分离,在操作系统与硬件之间加入一个虚拟化软件层,通过空间上的分割、时间上的分时以及模拟,将服务器物理资源抽象成逻辑资源,向上层操作系统提供一个与它原先期待一致的服务器硬件环境,使得上层操作系统可以直接运行在虚拟环境上,并允许具有不同操作系统的多个虚拟机相互隔离,并发运行在同一台物理机上,从而提供更高的IT资源利用率和灵活性。

计算虚拟化的虚拟化软件层需要模拟出来的逻辑功能主要为高效、独立的虚拟计算机系统,我们称之为虚拟机,在虚拟机中运行的操作系统软件,我们称之为Guest OS。

计算虚拟化技术可以将单个CPU模拟为多个CPU,允许一个平台同时运行多个操作系统,并且应用程序可以在相互独立的空间内运行而互不影响。简单地说,计算虚拟化技术实现了计算单元的模拟和模拟出来的计算单元间的隔离。

虚拟化软件层模拟出来的每台虚拟机都是一个完整的系统,它具有处理器、内存、网络设备、存储设备和BIOS,因此虚拟机中运行的操作系统和应用程序与在物理服务器上运行的操作系统和应用程序并没有本质的区别。

计算虚拟化的这个软件层,也就是虚拟机监控器(Virtual Machine Monitor, VMM),通常被称为Hypervisor。常见的Hypervisor软件栈架构方案分为两类,即Type-I型和Type-II型。

Type-I型(裸金属型)指VMM直接运行在裸机上,使用和管理底层的硬件资源,GuestOS对真实硬件资源的访问都要通过VMM来完成,作为底层硬件的直接操作者,VMM拥有硬件的驱动程序。Type-II型(宿主型)指VMM之下还有一层宿主操作系统,由于Guest OS对硬件的访问必须经过宿主操作系统,因而带来了额外的性能开销,但可充分利用宿主操作系统提供的设备驱动和底层服务来进行内存管理、进程调度和资源管理等。

我们进一步分析Hypervisor对于CPU指令的模拟和虚拟实例的隔离方式,计算虚拟化技术可以细分为如下几个子类。

一、全虚拟化(Full Virtualization)

全虚拟化是指虚拟机模拟了完整的底层硬件,包括处理器、物理内存、时钟、外设等,使得为原始硬件设计的操作系统或其他系统软件完全不做任何修改就可以在虚拟机中运行。操作系统与真实硬件之间的交互可以看成是通过一个预先规定的硬件接口进行的。全虚拟化VMM以完整模拟硬件的方式提供全部接口(同时还必须模拟特权指令的执行过程)。举例而言,x86体系结构中,对于操作系统切换进程页表的操作,真实硬件通过提供一个特权CR3寄存器来实现该接口,操作系统只需执行“mov pgtable, %%cr3”汇编指令即可。全虚拟化VMM必须完整地模拟该接口执行的全过程。如果硬件不提供虚拟化的特殊支持,那么这个模拟过程将会十分复杂。一般而言,VMM必须运行在最高优先级来完全控制主机系统,而Guest OS需要降级运行,从而不能执行特权操作。当Guest OS执行前面的特权汇编指令时,主机系统会产生异常(General Protection Exception),执行控制权将重新从Guest OS转到VMM手中。VMM事先分配一个变量作为影子CR3寄存器给Guest OS,将pgtable代表的客户机物理地址(Guest Physical Address)填入影子CR3寄存器,然后VMM需要将pgtable翻译成主机物理地址(Host Physical Address)并填入物理CR3寄存器,最后返回到Guest OS中。随后VMM还将处理复杂的Guest OS缺页异常(Page Fault)。比较著名的全虚拟化VMM有Microsoft Virtual PC、VMware Workstation、Sun Virtual Box、Parallels Desktop for Mac和QEMU。

二、超虚拟化(Paravirtualization)

这是一种修改Guest OS部分访问特权状态的代码以便直接与VMM交互的技术。在超虚拟化虚拟机中,部分硬件接口以软件的形式提供给客户机操作系统,这可以通过Hypercall(VMM提供给Guest OS直接调用,与系统调用类似)的方式来提供。例如,GuestOS把切换页表的代码修改为调用Hypercall来直接完成修改影子CR3寄存器和翻译地址的工作。由于不会产生额外的异常和模拟部分硬件执行流程,超虚拟化可以大幅度提高性能,比较著名的VMM有Denali、Xen。

三、硬件辅助虚拟化(Hardware-Assisted Virtualization)

硬件辅助虚拟化是指借助硬件(主要是主机处理器)的支持来实现高效的全虚拟化。例如有了Intel-VT技术的支持,Guest OS和VMM的执行环境自动地完全隔离开来,Guest OS有自己的“全套寄存器”,可以直接运行在最高级别。因此在上面的例子中,Guest OS能够执行修改页表的汇编指令。Intel-VT和AMD-V是目前x86体系结构上可用的两种硬件辅助虚拟化技术。

四、部分虚拟化(Partial Virtualization)

VMM只模拟部分底层硬件,因此客户机操作系统不做修改是无法在虚拟机中运行的,其他程序可能也需要进行修改。在历史上,部分虚拟化是通往全虚拟化道路上的重要里程碑,最早出现在第一代的分时系统CTSS和IBM M44/44X实验性的分页系统中。

五、操作系统级虚拟化(Operating System Level Virtualization)

在传统操作系统中,所有用户的进程本质上是在同一个操作系统的实例中运行的,因此内核或应用程序的缺陷可能会影响其他进程。操作系统级虚拟化是一种在服务器操作系统中使用的轻量级的虚拟化技术,内核通过创建多个虚拟的操作系统实例(内核和库)来隔离不同的进程,不同实例中的进程完全不了解对方的存在。比较著名的虚拟化技术有Solaris Container、FreeBSD Jail和OpenVZ等。

接下来我们对当前比较热门的Xen和KVM这两种虚拟化方案进行详细的介绍。

4.1.2 Xen虚拟化技术

Xen是由剑桥大学计算机实验室开发的一个开源项目,可以直接运行在计算机硬件上,并且可以并发地支持多个客户操作系统。Xen能够支持多种处理器,如x86、x86-64、Power PC和ARM等,所以其可以运行在较多种类的设备上。目前Xen支持的客户操作系统有Linux、NetBSD、FreeBSD、Solaris、Windows和其他一些常用的操作系统。

Xen包含三种基本组件,分别是Hypervisor、Domain 0和Domain U。

Hypervisor运行在物理硬件之上,承载所有的客户操作系统,主要负责向物理硬件设备上的所有的操作系统提供CPU调度和内存分配等功能。Hypervisor隔离了物理硬件和操作系统,从而提高客户操作系统的安全性。

Domain 0运行在Hypervisor之上,是Xen的管理员,具有直接访问硬件和管理其他客户操作系统的权限。在Domain 0中,存在两个基本的驱动,分别是网络驱动程序和块存储驱动程序。网络驱动程序能够直接与本地的网络硬件进行通信,从而处理来自于客户操作系统的网络请求。类似地,块存储驱动程序能够与本地的存储设备通信,处理客户操作系统的数据读写请求。

Domain U运行于Hypervisor之上,是Xen虚拟环境中的客户虚拟机。Domain U上运行的客户操作系统有两类,一种是半虚拟化客户机,另一种是完全虚拟化客户机。半虚拟化客户机上运行的操作系统,是经过修改之后的。而完全虚拟化客户机上的操作系统,则是未被修改的标准的操作系统。Xen虚拟环境中可以同时运行多个Domain U。

目前Xen支持三种虚拟化方案,分别是超虚拟化、完全虚拟化和IO半虚拟CPU完全虚拟化方案。

在超虚拟化方案中,客户虚拟机操作系统可以感知自己的运行环境不是物理硬件,而是在Hypervisror之中,同样也可以感知到其他的客户虚拟机。客户虚拟机的操作系统,为了能够调用Hypersivor,需要对操作系统进行专门的修改。把标准的操作系统移植到Xen架构中,才能够运行到客户虚拟机上。

在完全虚拟化中,客户虚拟机操作系统所感知的运行环境则始终是物理硬件,并且无法感知到在相同环境下的其他正在运行的客户虚拟机。所有的客户虚拟机上运行的,都是标准的不需要修改的操作系统。

而第三种方案,则对前两种方案结合起来。在完全虚拟化的客户虚拟机上安装使用特殊的超虚拟化设备驱动。因为超虚拟化的设备驱动具有更好的性能,所以本方案能够使完全虚拟化的客户虚拟机具备更好的性能。

4.1.3 KVM虚拟化技术

KVM(Kernel-based Virtual Machine)是基于Linux内核的开源的虚拟化解决方案。KVM从2.6.20版本开始被合入kernel主分支维护,成为Linux的重要模块之一,截止到目前已经实现了对x86、S390和PowerPC等体系结构的支持。

KVM本身只能够提供CPU虚拟化和内存虚拟化等部分功能,而其他设备的虚拟和虚拟机的管理工作,则需要依靠QEMU来完成。在KVM虚拟化环境中,一个虚拟机就是一个传统的Linux进程,运行在Qemu-KVM进程的地址空间。KVM和QEMU相结合,一起向用户提供完整的平台虚拟化。在KVM虚拟化方案中,通过在Linux内核中增加虚拟机管理模块,直接使用Linux非常成熟和完善的模块和机制,例如内存管理和进程调度等,从而使Linux内核成为能够支持虚拟机运行的Hypervisor。

KVM虚拟化方案中使用了VT-x的VMX(Virtual Machine eXtension)模式。在这种模式下,CPU具有根模式和非根模式两种操作模式,而每种操作模式又分别具有独立的Ring0和Ring3。在KVM虚拟化场景中,KVM主机在根模式下运行,主机的kernel处于Ring0级别,而用户态程序则处于Ring3级别。客户虚拟机运行在非根模式下,其中,kernel运行在非根模式中的Ring0,而其他用户态程序则在Ring3上运行。当处于非根模式中的主机(即客户虚拟机)执行敏感指令时候,会触发VM-Exit, CPU会从非根模式切换到根模式,也就是KVM主机会进行接管,对敏感指令进行一系列的处理。同样也存在从根模式到非根模式的VM-Entry切换,这种情况主要发生在Hypersivor调度启动客户虚拟机的时候。

当在KVM虚拟化环境中创建虚拟机时,首先运行在KVM主机用户态的Qemu-kvm会调用ioctl通过/dev/kvm设备创建虚拟机和虚拟CPU。Linux内核的KVM模块会创建和初始化相关的数据。之后会运行用户态的qemu-kvm,通过ioctl启动运行vCPU,之后内核会启动虚拟机,并且通过VM-Entry进入到客户虚拟机操作系统。在客户虚拟机中,操作系统会执行虚拟机的代码,如果是非敏感指令,可以直接在物理CPU上运行。如果执行到了敏感指令或发生异常时,就会触发VM-Exit并记录相关的信息,从而使CPU切换到根模式下,由Hypervisor来进行进一步的处理,处理完成后会触发VM-Entry进入到客户虚拟机操作系统中继续执行其他指令。

Xen和KVM都是当前非常热门的虚拟化技术,且具有各自的特点。Xen是较早出现的虚拟化技术,具有广泛的管理工具和较好的性能,同时支持半虚拟化和完全虚拟化,实现了对大多数CPU的支持。KVM是一个轻量级的虚拟化管理程序模块,来自于Linux内核,具有较好的性能和实施的简易性,以及对Linux的持续支持,但是目前只支持具有虚拟化功能的CPU。