第1章 QEMU与KVM概述
1.1 虚拟化简介
1.1.1 虚拟化思想
计算机科学家David Wheeler有一句名言:“计算机科学中的任何问题都可以通过增加一个中间层来解决。”这句话简洁而深刻地说明了虚拟化的思想存在于计算机科学中的各个领域。虚拟化的主要思想是,通过分层将底层的复杂、难用的资源虚拟抽象成简单、易用的资源,提供给上层使用。本质上,计算机的发展过程也是虚拟化不断发展的过程。
CPU内部遍布的数字逻辑电路只能够识别二进制数据0、1,机器码是计算机唯一能够识别的数据。汇编语言的出现让程序员能够比较简单地实现CPU的执行和内存访问。C语言的出现进一步方便了程序员,使得程序员可以从具体CPU架构指令脱离出来,大部分情况下只需要考虑业务即可。Python、Java等现代高级语言更是重新定义了自己的指令,由各个平台的虚拟机去解释执行,实现了完全的跨平台。从机器码、汇编语言到C语言,再到高级语言,其本质就是一个不断虚拟的过程,将底层复杂的接口转变成了上层容易使用的接口。
硬盘由柱面、磁道、扇区构成,里面存放着文件等数据信息,计算机用户在进行文件访问的时候并不需要关心这些底层细节。这些细节经过操作系统的抽象,变成了文件与目录的概念,使得复杂的硬盘数据管理变得简单方便,应用程序能够通过文件管理的接口方便地创建、读取、写入文件,这本质上也是一种虚拟。
TCP/IP协议栈模型是另一个虚拟化的例子。网卡设备传递的都是二进制数据,经过网络层、传输层的抽象之后,应用程序不需要直接跟网络数据包的收发细节打交道,只需要关心协议栈最上层的接口,也不需要关心其他使用网卡设备的程序,只需要将要发送的数据和地址提供给协议栈,协议栈会自动处理好IP路由、分片等细节。
现代操作系统中都有很多进程,每一个进程都是对计算机的抽象,进程都认为自己独占整个计算机系统的资源,有着独立的CPU和内存。但这些都是操作系统呈现给进程的假象,操作系统通过在各个进程之间共享CPU,为每个进程创建独立的虚拟内存,这不仅能够实现资源的充分利用,也能够实现进程之间的安全隔离。
操作系统会提供一组接口给应用程序,方便开发者编写应用程序,比如创建进程操作文件、发送网络数据等,这种抽象本质上也是虚拟化的一种体现。开发者只需要关注上层的接口而不需要关心底层的细节实现。这样底层的实现即使发生了变化,也不会影响上层应用程序的运行,如Wine项目和Cygwin项目,前者能够让为Windows编写的程序运行在Linux上,后者能够让为Linux编写的程序运行在Windows上。
以上的例子都是虚拟化思想的体现。底层的资源或者通过空间的分割,或者通过时间的分割,将下层的资源通过一种简单易用的方式转换成另一种资源,提供给上层使用。经典的操作系统书籍Operating Systems:Three Easy Pieces从三个方面讲述了操作系统的基本原理,第一部分即是虚拟化思想,其他两部分是并行和持久化。
1.1.2 虚拟机简介
上一节阐述了虚拟化的思想,本节介绍一下虚拟机(Virtual Machine,VM)。虚拟机,顾名思义,其重点在“机”上,也就是机器。理论上讲,只要能提供一个执行环境,完成用户指定任务的对象都可以叫作机器。所以可以从多种角度来解释虚拟机。
最简单的虚拟机是进程,这种虚拟机太过于普通,以至于很多人都没有意识到它们是虚拟机。进程可以看作是一组资源的集合,有自己独立的进程地址空间以及独立的CPU和寄存器,执行程序员编写的指令,完成一定的任务。一个进程在执行指令、访问内存的时候并不会影响其他进程。这是通过操作系统完成的,操作系统把CPU按照时间分配复用,把内存按照空间分配复用,通过管理底层资源,使得进程都能够使用整个计算机的物理资源,每个进程都认为自己拥有整个机器。操作系统上可以创建很多个进程,每一个进程都可以看成是一个独立的虚拟机。进程虚拟机如图1-1所示。
图1-1 进程虚拟机
模拟器是另一种形式的虚拟机。进程的指令都是可以直接运行在硬件CPU上的,模拟器则不同,它可以使为一种硬件指令集(Instruction Set Architecture,ISA)编译的程序运行在另一种硬件指令集上。应用程序在源ISA(如ARM)上被编译出来,在模拟器的帮助下,运行在不同的目标ISA(比如x86)上。模拟器可以通过解释来实现,即对程序的源ISA指令一条一条进行分析,然后执行相应的ISA指令上的操作。模拟器也可以通过二进制翻译实现,即首先将程序中所有的源ISA指令翻译成目标ISA上具有同样功能的指令,然后在目标ISA指令机器上执行。模拟器的基本原理如图1-2所示。典型的模拟器有QEMU(Quick Emulator)的用户态程序模拟、Bochs模拟器等。
高级语言虚拟机在模拟器的基础上更进一步,将源ISA和目标ISA完全分离开。在高级语言虚拟机中,通常会设计一种全新的虚拟ISA,并在其中定义新的指令集、数据操作、寄存器的使用等类似于物理ISA中的规范。不同于普通程序和模拟器运行的程序,高级语言虚拟机的程序中没有任何具体物理ISA指令字节,而是自己定义虚拟的指令字节,这些指令字节通常叫作字节码。任何想要运行这种虚拟ISA指令的物理ISA平台都需要实现一个虚拟机,该虚拟机能够执行虚拟机ISA指令到物理ISA指令的转换。程序员通过使用高级语言编写程序,不需要考虑其具体的运行平台,即可非常方便地实现程序的跨平台分发。高级语言虚拟机如图1-3所示。典型的高级语言虚拟机有JVM虚拟机、Python虚拟机等。
图1-2 模拟器原理
图1-3 高级语言虚拟机
在高级语言虚拟机中,虚拟ISA是公开的规范,每个人都可以获得,并且可以自己写出反编译的工具,通过字节码来还原程序的源码。这也是为什么使用Java语言的程序常常需要进行代码混淆。假设我们自己定义一个虚拟的ISA,但是并不公开其规范,并且可以时不时地修改这些规范,然后将自带的虚拟机和字节码合起来一起进行分发,这样使用基于物理ISA的反编译工具就无法还原出程序的汇编代码,这就是软件保护中虚拟机保护的原理。
进程、模拟器、高级语言虚拟机提供的都是指令的执行环境,而系统虚拟机提供的是一个完整的系统环境。在这个环境中,能够运行多个用户的多个进程。通过系统虚拟化技术,能够在单个的宿主机硬件平台上运行多个虚拟机,每个虚拟机都有着完整的虚拟机硬件,如虚拟的CPU、内存、虚拟的外设等,并且虚拟机之间能够实现完整的隔离。早期系统虚拟机诞生的原因主要是大型计算机系统非常庞大且昂贵,需要多个用户共享,而用户希望可以自由地运行其需要的操作系统。在系统虚拟化中,管理全局物理资源的软件叫作虚拟机监控器(Virtual Machine Monitor,VMM),VMM之于虚拟机就如同操作系统之于进程,VMM利用时分复用或者空分复用的办法将硬件资源在各个虚拟机之间进行分配。系统虚拟机原理如图1-4所示。典型的系统虚拟化解决方案包括VMware Workstation、QEMU、VirtualBox和HyperV等。
图1-4 系统虚拟机
1.1.3 系统虚拟化的历史
虚拟化基本上是与操作系统同时出现的,早在大型机时代就已经存在了,如20世纪60年代IBM的分时系统。那个时候的计算机普遍比较昂贵,系统虚拟化的主要目的是在多用户之间实现物理资源的共享。随着之后计算机的不断发展、计算机价格的下降以及个人计算机的普及,用户对虚拟化的需求大大减少,系统虚拟化技术的发展也逐渐没落了下来。
随着硬件技术的再次发展,普通PC也能够支持多个系统同时运行,虚拟化又重新出现在人们的视野中,VMware在1998年的成立标志着虚拟化的全面复兴,随后2001年剑桥大学开发了Xen。
随着云计算概念的提出与实践的落地,虚拟化更加有了用武之地。虚拟化能够将一台小型服务器或者普通PC虚拟出多个虚拟机,每个虚拟机都可以以计算资源的形式出售给租户,这样不仅能够提升资源的利用率,还能够非常方便地删除/创建各种规格的虚拟机,提供按需分配的功能。
系统虚拟化在云计算的支持下得到了非常迅速的发展,如之前的x86架构不支持硬件层面的虚拟机,导致VMM的设计和实现都比较麻烦,并且性能也不是很好。为了克服x86架构的虚拟化缺陷,Intel和AMD都相继在CPU硬件层面增加了虚拟化的支持。随着用户对性能需求的不断提升,内存、外设等也在硬件层面提供了对虚拟化的支持。
2006年,以色列的初创公司Qumranet利用Intel的硬件虚拟化技术在Linux内核上开发了KVM(Kernel Virtual Machine)。KVM架构精简,与Linux内核天然融合,得以很快进入内核。后来Red Hat收购了Qumranet,全力投入到KVM的建设中。KVM现在已经是一个非常成功的虚拟化VMM,广泛应用在各种开源云平台上,成为云计算的基石。
如同操作系统一样,虚拟化方案也有很多,这里简单介绍几个。
● VMware Workstation:VMware最早的产品,至今仍有大量用户使用。VMware Workstation能够很方便地在PC上构建一个虚拟机,用户可以在其上安装各种操作系统,能够非常方便地完成多种任务,比如跨平台的开发测试,不需要再独立使用一个单独的宿主机。比如在进行恶意软件的分析时,一般情况下不需要担心病毒会破坏自己的计算机。
● VirtualBox:最早由一个德国公司开发,后来被甲骨文收购。它的优点是性能不错并且开源,能够很方便地用来实现一些定制需求,但是不如VMware Workstation稳定。
● HyperV:微软提供的虚拟化解决方案,微软用它来构建自己的云计算平台。
● Xen:早期的开源虚拟化方案,出现在各种硬件虚拟化技术之前。它的设计有很多不可避免的问题,比如虚拟机的内存管理需要与Xen一起协作完成,这导致了非常多的安全问题。虽然后来Xen也支持利用硬件虚拟化的虚拟机,但是其发展已经远不如KVM。即便如此,Xen作为早期的开源VMM,其诸多思想直到今天也在影响着虚拟化社区。