2. XEN:方法和概述 在传统的VMM中,虚拟硬件的功能是与底层机器上的真实硬件完全相同的。这种“完全虚拟化”(full virtualization)的方法最显而易见的好处在于操作系统可以不经任何修改就直接在虚拟硬件上运行,但是它也有很多缺点。特别是针对那些当前被广泛应用的IA32(或者称作x86)架构,这种方法带来的缺陷更是不容忽视。
x86架构的设计从来就不支持完全的虚拟化。如果要正确实现x86架构虚拟化,VMM就必须能够对某几条特定的“超级指令(supervisor instruction)”进行操作。但是,如果在没有足够特权的情况下执行这些超级指令会导致“沉默的失败(//fail silently:如果特权级不够,那么会直接导致执行失败,不会产生其它响应)”,而并非产生一个便于我们使用的陷阱(trap)。
另外,将x86架构中的MMU进行有效的虚拟化也是一件很困难的事情。这些问题是可以被解决的,但是在解决的同时必须要付出操作复杂度增加和系统性能降低的代价。VMware ESX Server[10]需要动态地重写那些被VMM操控的机器码部分,在其中有可能需要VMM干涉的地方插入陷阱操作(//在什么地方插入陷阱操作,是在程序运行起来后才知道的,所以需要动态地重写相关代码)。因为务必要对所有那些不能够引起陷阱的特权指令进行捕捉和操作,所以这种转换(//动态重写代码)要被应用于整个guest OS的内核(导致了相关的转换,执行和缓存等开销)。ESX Server实现中采用的技术是建立系统结构(system structure)(比如页表)的影子版本,通过为每一次“更新”操作设立陷阱来解决虚拟页表和物理页表的一致性问题(//具体细节还是要看ESX Server的说明)。但是在处理“更新密集”型的操作(如创建新的应用进程)的时候,该方法会带来高昂的开销。
除了x86架构非常复杂的原因,还有一些其它方面的争论反对“完全虚拟化”。其中值得一提的是,被操控的操作系统在一些情况下需要接触到真实的资源。例如,提供真实时间和虚拟时间以允许guest OS能够更好地支持“时间敏感”型的任务,还可以正确地操作TCP超时和RTT估算;给出真实的机器地址以允许guest OS能够利用超级页(superpage)或者页染色(page coloring)等方法改进性能。
我们提出的虚拟机抽象能够避免完全虚拟化带来的种种缺陷。这种虚拟机抽象和底层硬件相似却并不完全相同,因此被称之为“准虚拟化”(//paravirtualization:或者翻译为半虚拟化?后面译文沿用准虚拟化)方法。这种方法虽然需要对guest OS进行一些改动,但是它能够改善性能。还有特别重要的一点需要说明:准虚拟化方法不会对应用二进制接口(ABI)进行修改,因此用户也就不用修改那些在guest OS上执行的应用程序。
我们进行的关于准虚拟化方法的讨论要遵循以下一些规则:
1.最基本的是要支持那些不经改动的应用二进制文件的执行,即用户不用对应用程序做针对Xen的转换。因此我们必须虚拟化现有的标准ABI所需的全部体系结构特征。
2.很重要的一点是要支持完整的多应用操作系统。这就需要将在单个guest OS实例中的复杂的服务器配置虚拟化(//例如,如果guest OS上配置了ftp服务,那么虚拟硬件就要打开相应端口)。
3.准虚拟化务必要有很高的性能。另外针对那些不协作(//uncooperative:这里的不协作是指硬件架构不支持共享,所以才需要资源隔离)的机器架构,如x86架构,准虚拟化还需要能够提供很强的资源隔离能力。
4.在协作(cooperative)的机器架构上,准虚拟化方法要能够完全地隐藏资源虚拟化带来的影响,减少guest OS在正确性和性能上面临的风险。
请注意,我们在这里提出的准虚拟化的x86抽象的方法是与最近在Denali项目中提出的方法有很大差异的。Denali是为了支持数以千计的运行着网络服务的虚拟机而设计的。这些网络服务中绝大部分是小规模的,不流行(//应用的不流行也就说明了运行该应用的环境比较少,所以只要针对这些相应的特定环境作专门的虚拟化即可)的应用。与之相反的是,Xen的设计最终要支持近100个运行着业界标准应用和服务的虚拟机。由于设计目标的极大差异,我们不妨将Denali的设计选择和我们自己的设计规则做一个有益的讨论。
首先,Denali不需要关注现有的ABI,因此他们的VM接口忽略掉了相关的架构特征。例如,Denali并不完全支持x86的分段机制,但是这一点却是在NetBSD,Linux和Windows XP等操作系统的ABI中都有提出并且被广泛使用。例如,线程库中经常会使用分段机制来寻址线程局部数据。
其次,Denali的实现没有解决在单个guest OS中支持多个应用(application multiplexing)的问题,也没有解决多地址空间的问题。应用被显式地链接到Ilwaco guest OS实例上,这么做在某种意义上类似于之前在Exokernel中的libOS[23]。因此每个虚拟机只能操控一个单用户单应用的没有保护措施的所谓的“操作系统”。在Xen中,与之相反,每个虚拟机上能够操控一个真正的操作系统。这个操作系统上能够安全地执行数以千计个不经改动的用户级进程。虽然Denali号称开发了一个虚拟MMU原型能够对其在该领域有所帮助,但是我们没有看到公开的技术细节和评估报告。
再次,在Denali体系结构中,是由VMM执行全部的内存与磁盘间的页面调度的。这可能是与虚拟层缺乏存储管理支持有关。由VMM完成页面调度是与我们的性能隔离目标相违背的:那些“有恶意”的虚拟机可能会故意产生抖动行为,导致其它虚拟机的CPU时间和磁盘带宽被不公平地剥夺(//VMM监控很多VM,各个VM上再跑操作系统,所以如果很多事情都放在VMM中做必然会影响到各个VM;所以要把一些事情放在上面的操作系统做来达到隔离性)。在Xen中,我们希望每个guest OS在其自己分配到的内存空间和磁盘区域内执行它自己的页面调度(此前已经有self-paging的方法被提出)。
最后,Denali为机器的全部资源虚拟了“名字空间”。这样的话,如果一个VM不能够“叫出”另一个VM下辖的资源的名字,那么该VM就不能够访问这些资源(例如,Denali中的VM并不知道硬件地址,它们只看得到Denali创建的虚拟地址)。与此相对,我们认为hypervisor中的安全访问控制已经足以确保安全性;此外,就像之前讨论过的,当前在guest OS是否应该能够直接看到物理资源这一点上存在着很热烈的关于正确性和性能的争论。
在后续的章节里,我们将描述Xen提出的虚拟机抽象,然后将讨论如何将一个guest OS作必要的改动以适应Xen。在这篇文章里我们定义了一些术语要提醒大家注意。例如,术语guest OS是指Xen能够操控的操作系统之一;术语domain是指一个运行中的虚拟机,在其上有一个guest OS在执行。program和process之间的区别和传统系统中的区别类似。我们称Xen本身为hypervisor,因为它运行的特权级要比它所操控的guest OS中的supervisor code运行的特权级更高。
2.1 虚拟机接口 一个准虚拟化的x86接口主要包括了系统中的三个大的方面:存储管理,CPU和设备I/O。在下面,我们将依次介绍各个机器子系统的情况,并讨论在我们的准虚拟化架构中是如何体现的。虽然在我们的实现中,有相当一部分,如存储管理,是专门针对x86的,但是实际上还有很多方面(比如我们虚拟的CPU和I/O设备)都是可以很容易地应用于其它机器架构上的。更进一步地说,在与RISC架构在实现上有差异的很多地方,x86往往表现出的是该方面最坏情况时的情形。例如,对硬件页表进行有效的虚拟化就比虚拟化一个软件管理的TLB困难很多。
存储
管理分段不能够使用具有完全特权级的段描述符,不能够与线性地址空间的最顶部交迭(//因为最顶部是Xen)。
分页guest
OS直接对硬件页表做读访问,但是更新(//就是写)是分批进行的而且要经过hypervisor确认。一个domain可以被分配在不连续的页面上。
CPU保护guest OS必须运行在低于Xen的特权级上。
异常guest OS必须将异常句柄的描述符表在Xen中记录。除了页面错误外,其它句柄和真实的x86架构相同。
系统调用guest OS为系统调用提供一个“快速”的句柄。允许应用直接调用它所在的guest OS,而不必间接地通过Xen完成每次调用。
中断硬件中断被一个轻量级的事件系统替换。
时间每个guest OS具有一个定时器接口,可以得到“真实的”和“虚拟的”时间。
设备I/O网络,磁盘,……虚拟设备访问起来很简单。数据传递使用的是异步I/O环。由一个事件机制替换硬件中断来发布通告。
2.1.1存储管理 虚拟化存储毫无疑问是准虚拟化一个体系结构中最困难的部分,它包括hypervisor所需的机制和移植各个guest
OS所需的改动。如果在架构中提供了由软件管理的TLB的话,那么这个任务会变得轻松些,它们可以以比较简单的方式被有效地虚拟化[13]。带标记的TLB是另外一个在大部分RISC架构(这些RISC架构主要用于构建服务器,比如Alpha,MIPS和SPARC)中支持的有用特征。其中,每个TLB项都有和地址空间标识符相关的标记,这使得hypervisor和各个guest OS能够有效地在被隔离开的地址空间内共存。这时在执行转移(//transferring execution:在进程执行间切换的时候,执行的指令序列从一个进程转移到另一个进程,称为执行转移)的时候,是不需要刷新(flush)整个TLB(//只对具有和自己的地址空间标识符相吻合的TLB项进行操作)。
不幸的是,x86架构并没有由软件管理的TLB;取而代之的是在发生TLB失效的时候,处理器会自动通过遍历硬件页表结构来处理。因此为了获得最好的可能达到的性能,当前地址空间内所有的有效页传输)都要在硬件可访问的页表中给出(//最好情况理应如