csatblogspotdotcom

Monday, May 19, 2008

读《An Overview of Virtual Machine Architectures》[1]

这篇文章主要介绍了虚拟机的概念,分类,起源,以及必要性。

早期的计算机是这样设计的:硬件首先被设计出来,软件是专门针对相应硬件而设计的。每个系统都有着自己的指令集,而软件则针对这个特殊的指令集设计。这些软件包括操作系统,汇编程序(以及后来的编译程序),还有应用程序。只需要一个小用户社区,相对简单的程序,和固定的硬件。但当用户群体扩大时,操作系统变得越来越复杂,应用程序也迅速增加,于是为每一个新的计算机系统重写和发布软件都成为一个艰巨的任务。

于是软件兼容性和可移植性的必要性显得格外重要。与此同时,各个计算机公司的硬件设计者也趋向于体现一定共同的硬件特征。新的设计往往与以往的设计类似。直到20世纪60年代初的IBM360家族,充分的软件兼容性被充分的认识并被明确的提出。IBM360系列有许多模型,覆盖了大范围的硬件资源,因此提供了不同性能和价格层次,而这些机器可以运行同样的软件。

为了达到这一点,软硬件间的接口必须被严格的定义与控制,系统指令集(ISA Instruction Set Architecture)的概念被提出。

除此之外,操作系统被设计为可以对应用程序屏蔽硬件异构性。操作系统负责管理硬件资源,保护正在运行的应用程序和用户数据,支持控制共享,并提供其他有用的功能。由于应用程序对操作系统提供的服务有很强的依赖性,这些操作系统服务和操作系统接口也变为标准化中重要的一个环节。到今天为止,仅有少量的标准操作系统。此外,操作系统不再彼此独立的工作,他们通过计算机网络负责资源和数据的共享。

为使软件与硬件匹配而设计的标准化接口使大规模复杂的和各种各样的软件系统能被开发出来。正是这些标准化接口,软件才能更灵活而且有更好的可移植性。然而,这还并不能称得上完美,因为有一些不同的,互不兼容的ISA和操作系统,因此软件可移植性受到这个软件开发平台的限制。用户程序被限制到一个特定的指令集和一个特定的操作系统。简言之,软件只能运行在一个特定类型的物理机器上。

虚拟机(VM Virtual Machine)可以解决这一物理机限制并提供更大限度的可移植性和灵活性。虚拟机是这样实施的,在一个执行平台上增加一层软件让他被上层软件看来完全是另外一个甚至是几个不同平台.虚拟机可以运行那些运行在相应物理机上OS或ISA之外的OS或ISA.

处理器,内存,I/O设备,网络资源都可以被虚拟化.当一个处理器或系统的状态处于虚拟化时,它实质上与一块特定的物理硬件分离.这意味着一个虚拟程序或系统能暂时与特定的物理资源关联起来,而这种关联能被实时的改变.

虚拟化技术能增强系统安全性,提升系统性能,简化软件迁移,并使基于网络的与平台无关软件成为可能.

传统的计算机系统体系结构有许多优点.主要的系统设计工作分离开来,硬件设计者和软件设计者可以相对独立的工作.事实上,,硬件,OS,应用程序这3个主要组成部分通常都由不同的公司在不同时间(甚至是相隔数年)开发.应用程序开发者不需要弄清楚OS内部的变化,硬件和软件能根据不同的进度被升级.软件能在具有相同ISA的不同硬件平台上运行.正因为这种体系架构所具有的优点使它持续存在了几十年,并吸引了大量投入.

然而,传统体系架构也有一些明显缺点.随着软硬件变得越来越复杂,计算机应用程序越来越多样化,这些缺点显得越来越突出.



主要部件仅在彼此恰好搭配时才正常工作.不同系统的部件不具备互操作的能力.为一个特定ISA编译的应用软件不能在一个有着不同ISA的硬件上运行.在一个严重依赖网络的环境中,这个问题变得更加突出.把一组用网线连接起来的计算机视为一个单一系统,而软件能在计算机件自由迁移,这样做有极大的好处.而传统计算机系统体系结构限制了这种灵活性.

第二个问题就是计算机系统更新或升级常常受到底层接口的限制,因为软件层需要支持那些已经被开发出几年甚至是几十年的底层接口.例如,一个新的软件概念的提出可能会受到一个老的"祖传的"ISA的限制.硬件开发可能也会由于要支持以前的ISA而受到限制,一些高性能的革新也会受到限制.而且,即使ISA经过扩展,支持新的革新(实际情况也常常如此),他们同时也必须支持老的ISA,而这些老ISA又很少用到,成为冗余的包袱.

第三个问题就是跨接口(软硬件间)的优化很难实现.软硬件开发者一般在不同公司,而且一般在不同时间,彼此很少交流,所以让他们合作跨越接口来对系统进行优化是一件很难的事情.例如,应用软件和硬件的独立开发意味着程序二进制代码并非为某个特定的硬件而作优化.通常只有一个版本的二进制代码被发布,它很有可能就只为一个处理器模型作了优化(如果它做过优化的话).此外,编译器的开发常常滞后于处理器的开发,所以相应二进制代码常常针对一个早期版本处理器作优化,而不是针对它们正在运行的处理器.

最后,在一个传统计算机系统中,一个操作系统与一个硬件平台匹配,所有应用程序都在单一OS的管理与保护下共存.这不仅使所有用户都被限制在同一OS下,而且因为系统软件的共享使OS存在一些安全问题.

在计算机系统中,对于不同层面的抽象,看到的"机器"也不同.从"进程"(process)的角度,机器包括一个已经分配给进程的内存地址空间,一些用户级寄存器,以及能使该进程执行自己代码的那些指令.I/O系统对于进程来说是很抽象的东西.磁盘和其他辅存就是一些能被它们访问的文件的集合.在桌面环境中,进程通过GUI中的窗口与用户交互.而进程与I/O系统交互的唯一方式是操作系统调用,不管是直接还是通过提供给进程的库.

而从一个更高层次来看,底层"机器"支持着一整个"系统"(system).一个系统是一个能同时支持属于不同用户的进程的完全的执行环境.所有进程共享同一文件系统和其他I/O资源.系统环境持续存在,其间不断有进程产生和消亡.系统分配物理内存和I/O资源给进程,使进程通过OS与属于它们的资源交互.

正如一个"机器"的概念可以从进程角度看也可以从系统角度看,虚拟机也可以有进程级别和系统级别的.正如其字面意思,一个进程虚拟机能支持单个进程.它随进程的产生而产生,随进程的终止而终止.例如,Intel x86PC运行Linux,其上通过Java虚拟机运行Java进程.Java虚拟机环境能通过Java库执行Java字节码程序并进行I/O操作.同样的系统也可以通过能对PowerPC指令进行仿真的进程级虚拟机来支持PowerPC/Linux应用程序.所有这些进程都能同时存在于同一系统环境中,彼此之间可以交互.例如一个PowerPC进程能生成一个x86进程并通过共享内存与之通信.如果是在一个桌面系统中,它们都由各自的独立窗口,并在同一X-windows的GUI中出现.

一个系统级的虚拟机提供一个完备的系统环境.这个环境支持多用户进程,包括一个文件系统,为进程提供I/O设备访问权限,而且对于桌面,它支持GUI.

对于实现虚拟机来说,有两种重要的标准化接口,它们大致对应了进程级虚拟化和系统级虚拟化.首先是ISA,包括用户和系统指令.用户指令可提供给应用程序和OS;系统指令包括特权操作,这些特权操作允许直接操作,分配,和观察读取(observation)共享的硬件资源(处理器,内存,I/O).

另一种是应用程序二进制接口(ABI, Application Binary Interface).ABI也有两个主要组成部分.第一个是所有用户指令组成的集合(系统指令并不属于ABI),第二个是系统调用接口.在ABI层面上,所有的应用程序通过系统调用接口调用OS来与共享的硬件资源间接的进行交互.




进程VM






进程级VM为用户应用程序提供一个虚拟的ABI环境,包括复制(replication),仿真(emulation),和优化(optimization).

多道程序设计(multiprogramming)

第一种也是最常见的VM,它是如此普遍以至于我们甚至没有认为它属于虚拟机.传统的多道程序设计为每个用户进程提供这样一个假象:自己拥有一整个属于自己的机器.每个进程都有一个属于自己的地址空间,并有权访问一个文件结构.OS使硬件被分时复用,并管理底层硬件资源.事实上,OS为每一个并发执行的应用程序提供被复制的进程级虚拟机.而且,这种进程的数量几乎不受限制:进程虚拟机可以被自由的复制.

仿真和动态二进制翻译(emulation and dynamic binary translators)



对进程级虚拟机提供来说,一个更具有挑战性的问题是让在一个指令集机器上编译的程序能运行于另一个不同指令集机器之上.应用程序针对一个源ISA被编译,但在另一个不同的目标ISA上被执行.由于是不同的ISA,所以需要虚拟机对源ISA的执行进行仿真.最直接的仿真的方法就是解释(interpretation).一个解释程序执行目标ISA的取指,译码,并模拟源指令的执行.这是一个相对缓慢的过程,一条源指令对应大量的当地指令(native instruction).

需要更好性能的话,二进制翻译是一种选择.在二进制翻译过程中,源指令块被转化为有等价功能的当地指令.翻译的过程可能会有相对较大的开销,但一旦一个指令块被翻译,就能被缓存起来并被复用,这整个过程要比解释快得多.因为二进制翻译常被用于进程VM,所以它们常被叫做动态二进制翻译.

解释和二进制翻译有着不同的性能特征.解释的启动开销较小,但当一条指令被仿真时会消耗大量时间.另一方面,二进制翻译有较大的初始化开销,但对每一个重复执行来说很快.结果,一些虚拟机借助剖析手段采用了分阶段仿真模型.起初,一块源指令被解释,同时用剖析手段来决定哪些指令序列经常被用到.然后,一个经常被用到的块被翻译.一些系统更进了一步,采用了代码优化措施:如果剖析表明某个块经常被用到,就对其进行优化.在大多数仿真虚拟机中,解释和翻译在单个程序整个运行过程中都出现.

动态优化(dynamic optimizers)

大多数动态翻译器都不仅仅把源代码翻译成目标代码,而且作一些优化工作.一个动态优化器在一个正在运行的程序上可以进行一些统计,例如建一个剖析文档(profile),然后用这些剖析信息来实时的对二进制代码进行优化.

高级别VM:完全独立于平台



对于以上描述的VM,跨平台的可移植性显然是一个很重要的目标.但仿真的方法有很大开销.相比之下,高级语言VM环境要更优.

传统系统的与平台无关代码的发布是这样一个过程:首先由编译器前端把高级语言程序转化为中间码,接着由编译器后端把中间码转化为针对特定系统的目标代码.这时目标文件就可以发布了.

对于高级语言虚拟机环境来说,过程有所不同.首先由编译器把高级语言程序编译为可移植代码.这时可移植代码就可以被发布了.然后由虚拟机执行可移植代码.

高级VM的优点在于只要VM能在目标平台上运行软件就能被彻底移植.尽管这会有些复杂,但比起为每个平台开发一个编译器并对每一高级语言应用程序进行重编译要简单得多,同时比起传统的进程VM要简单得多.

系统虚拟机(system virtual machines)



系统VM提供一个完备的系统环境,多个进程,甚至是属于多用户的不同进程可以共享.在20世纪60年代和70年代初,虚拟机的概念被提出.

在经典VM模型中,VMM置于硬件层之上,虚拟机在最上面.VMM运行在最高特权模式.VMM能以完全透明的方式截获并执行所有guest OS与硬件交互的行为.

系统VM的另一种实现方式把虚拟化软件置于一个已有的OS之上,它能利用下面的OS提供的设备驱动和其它底层服务.但这样做会损失一些性能.




全系统VM:仿真

在以上描述的"经典"系统VM中,所有OS和应用都必须和底层硬件的ISA保持一致.但在有些重要场景下,OS及应用同硬件的ISA不能保持一致,这样就导致了用仿真方式实现的系统VM的出现.透明被称作"全系统"(whole system)VM,因为把所有软件都虚拟化了.最常见的实现方法就是把VMM和软件置于运行在物理硬件上的传统OS之上.由于不易利用底层系统ISA特性(如虚拟内存管理和陷阱截取),所以仿真会受到很大限制,此外,如果host和guest硬件特性有很大不同,那么会出现很多问题.



1. http://www.cse.psu.edu/~bhuvan/teaching/spring06/papers/overview.pdf

Labels:

0 Comments:

Post a Comment

Subscribe to Post Comments [Atom]

<< Home