1.2.1 发展历史
1.早期虚拟化探索
虚拟化技术的发展历史与计算机技术一脉相承。早在1959年,牛津大学的计算机教授Christopher Strachey在信息处理国际大会(International Conference on Information Processing)发表了论文Time sharing in large fast computers[2],针对当时大型机器使用效率低下的问题(资源利用率低到现在也没有得到很好的解决,如何提升资源利用率贯穿整个计算机的发展历史),提出了具有虚拟化概念的高效分时复用方案,原文为“各种程序和外设竞争获得控制权(分时共享),并竞争获得存储的使用权(空间共享)”(There would be various programs and pieces of peripheral equipment competing both for the use of control(time sharing)and also for the use of the store(space sharing)),这被认为是虚拟化技术的最早表述。
论文中提出的Director监控程序被放置在一个可快速访问并且不可删除的存储介质上(保证了自身运行的高效性和完整性)。Director提供了一个隔离的运行环境,控制各个程序的分时运行,并确保各个程序无法相互干扰。这里的Director可以看作“一虚多”Hypervisor的雏形。同时,论文提出了虚拟机的概念(包括CPU和存储的完整状态),原文为“多个操作(程序)同时在物理机上运行,似乎跑在单独的机器上(虚拟机),但每个虚拟机比实际的物理机小一些、慢一些”(In this way,during the normal running of the machine several operators are using the machine during the same time. To each of these operators the machine appears to behave as a separate machine(smaller,of course,and slower than the real machine))。由此可见,虚拟化技术提供的“弹性”和“隔离”概念已经孕育于早期的系统设计中。
因此早期的资源虚拟化主要研究“一虚多”,即把单物理资源抽象成若干虚拟资源(如1个物理CPU可抽象成512个虚拟CPU)。在计算机技术发展的早期阶段,尚在探索对于计算资源的时分复用,以便多人能通过终端同时使用一台计算机,分享昂贵的计算资源,提高计算机的资源利用率。
1965年IBM M44/M44X实验项目实现了在同一台主机M44上模拟多个7044系统,突破了部分硬件共享(Partial Hardware Sharing)、分时共享(Time Sharing)和内存分页(Memory Paging)等关键技术,并首次使用术语“虚拟机”。这里模拟的虚拟机M44X并非完全与主机相同,与现在Xen采用的半虚拟化技术(1.3节将详细介绍该技术)异曲同工。在此基础上,IBM研发了一系列虚拟化技术,如CP-40/CMS、CP-67/CMS和CP370/CMS等,构成了完整的CP/CMS大型机虚拟化系统软件,一直延续到后来的IBM虚拟化软件z/VM。
20世纪60年代中期,IBM的CSC(Cambridge Scientific Center,剑桥科学中心)开发了CP-40/CMS,CP-40是虚拟机控制程序(Virtual Machine Control Program),其开发目标主要有4个:①研究资源的分时共享;②评估硬件对分时共享的需求;③开发内部使用的分时共享系统;④评估操作系统与硬件的交互行为。CP-40提供的虚拟机数量最多为14个,是第一个支持全硬件虚拟化(Full Hardware Virtualization)的系统。CP-40的后继系统CP-67[3]于1967年开发,其大小为80KB,可以运行于IBM的System/360-67大型机,提供多个虚拟的System/360机器实例,并可以通过CPREMOTE服务访问远程硬件资源,支持OS/360、DOS和RAX等客户机操作系统。此外,CP-67还有配套开发的专用客户机操作系统CMS(Cambridge Monitor System,剑桥监控系统),是一个不支持并发的单用户系统,以减小开销,其思想可以与今日的Unikernel类似。CP-67/CMS这套系统组合甚至比大家熟知的Multics和UNIX系统出现更早,但以虚拟内存和抢占式调度为首要特点的多用户操作系统很快占据了学术界和工业界的主流,而在很长一段时间内,虚拟化技术都没有引起人们足够的重视。因此早期虚拟化技术主要用于大型机,以至于后来设计x86指令集时就没有考虑虚拟化的需求[面向嵌入式和PC(Personal Computer,个人计算机)市场,虚拟化的性能开销也是其重要限制因素]。
2.虚拟化技术的普及
20世纪60至80年代,虚拟化技术主要用于大型主机。随着x86平台日益流行,特别是微软与英特尔的Wintel联盟主导全球PC市场,基于Linux的x86服务器也逐步侵蚀大型主机和小型机的市场份额,由此产生了对x86平台虚拟化的迫切需求,也推动了虚拟化技术的广泛普及。
20世纪80年代中期,Rod MacGregor创建的Insignia Solutions公司开发了x86平台的软件模拟器SoftPC,能在UNIX工作站上运行MS-DOS操作系统,1987年SoftPC被移植到苹果的Macintosh平台,并可以运行Windows操作系统。此后,一系列以软件模拟为主的PC虚拟化系统陆续发布,例如苹果开发的Virtual PC和开源的Bochs。
1997年,斯坦福大学Mendel Rosenblum教授等在计算机系统领域的重要国际会议SOSP(Symposium on Operating Systems Principles,操作系统原理研讨会)上发表了DISCO[4]。DISCO运行在具有共享内存的可扩展多处理器系统上,可以同时运行多个客户机操作系统。不同于SoftPC这样的软件模拟器,DISCO基于全虚拟化(Full Virtualization)技术(1.3.2节详细介绍),大部分用户态指令是直接运行在物理CPU上,使得虚拟化的开销大为降低。基于该原型系统,1998年Mendel Rosenblum教授等成立了著名的VMware公司,该公司也是目前x86虚拟化软件的主流厂商之一。1999年,VMware推出了广受欢迎的桌面虚拟化产品VMware工作站(VMware Workstation),也间接推动了x86虚拟化技术的普及。
2003年,剑桥大学Ian Pratt等学者在SOSP上发表了基于PV(Para-Virtualization(7),半虚拟化)技术(1.3.2节详细介绍)的代表性开源系统Xen[5]。与全虚拟化技术不同,半虚拟化技术需要修改客户机操作系统。通过客户机操作系统主动调用超调用(HyperCall)的虚拟化管理接口,能够进一步降低虚拟化的开销,并且由于Xen是开源系统,与Linux内核密切配合(半虚拟化技术需要修改操作系统,开源内核修改比较方便),Xen得到了广泛的应用,例如早期的亚马逊云计算平台EC2(Elastic Compute Cloud,弹性计算云)就是基于Xen构建的(EC2第一个采用半虚拟化的实例类型是m1.small)。
同年,法国天才程序员Fabrice Bellard发布了至今仍然使用的开源虚拟化软件QEMU(Quick EMUlator,快速仿真器),采用动态二进制翻译(Binary Translation)技术,能够支持多源多目标的跨平台仿真执行异构指令集,例如可以在x86平台上仿真运行ARM进程。QEMU是运行在用户态的仿真器,它不仅可以仿真异构指令集,还可以仿真整个机器,通过开源社区的不断改进,QEMU已成为目前使用最为广泛的开源软件仿真器(8)。
自2005年,x86硬件厂商开始从体系结构层面解决早期x86架构不符合虚拟化准则的问题(也称为“虚拟化漏洞”,2.1.1节详细介绍),避免纯软件全虚拟化方式(如二进制翻译)带来的性能、安全和可靠性的缺陷。Intel和AMD相继发布了基于硬件辅助的全虚拟化技术(Hardware-assisted Full Virtualization,1.3.2节详细介绍)。Intel的硬件辅助VT(Virtualization Technology,虚拟化技术)和AMD的类似技术SVM(Secure Virtual Machine,安全虚拟机)扩展了传统的x86处理器架构,客户机操作系统不用修改源码就可以直接运行在支持虚拟化技术的x86平台上,原来由软件模拟的大量特权操作直接由硬件执行,基本达到了物理CPU和内存的性能,虚拟化开销大为减少。
2006年,AWS(Amazon Web Services,亚马逊云服务)发布了S3(Simple Storage Service,简单存储服务)和EC2,开始以虚拟机形式向企业提供IT(Information Technology,信息技术)基础设施服务(基于开源Xen搭建),开启了以IaaS(Infrastructure as a Service,基础设施即服务)为代表性技术的云计算时代。
2007年2月,Linux Kernel 2.6.20中加入了以色列公司Qumranet开发的基于硬件辅助虚拟化的内核模块KVM(Kernel-based Virtual Machine,基于内核的虚拟机)。KVM由虚拟化领域另外一个天才程序员Avi Kivity带领开发,并于2006年10月19日首次在Linux内核社区发布,发布不到半年时间,Linux就将其正式纳入内核官方版本,由此也可以看出KVM对Linux开源社区的重要性和迫切性。Avi Kivity等提出的KVM充分遵循UNIX系统的设计原则,仅实现Linux内核态的虚拟化模块,用户态部分由上述的开源QEMU实现。由此,QEMU/KVM的虚拟化技术组合日益流行,成为目前主流的开源系统虚拟化方案,被各大虚拟化和云计算厂商采用。
基于KVM/QEMU的系列年度技术论坛(例如KVM Forum(9))也成为虚拟化技术的重要权威论坛,从2007年开始,KVM/QEMU的重要技术进展和年度汇报均发布于KVM Forum,是Linux虚拟化技术发展的一个窗口。近年来,国内华为、阿里和腾讯等虚拟化技术方面的专家也积极参加KVM Forum,凸显国内对虚拟化技术的贡献日益增加。
3.虚拟化技术蓬勃发展
从2010年开始,虚拟化技术不断扩宽应用场景,在移动终端、嵌入式和车载设备等资源受限的平台也开始被引入。同时,新型硬件虚拟化、“多虚一”虚拟化和轻量级容器虚拟化也取得了长足的进展,下面分别展开介绍。
1)新型硬件虚拟化
近年来大量新型硬件得到迅速普及,例如拥有数千个核的GPU(Graphics Processing Unit,图形处理单元)、具有RDMA(Remote Direct Memory Access,远程内存直接访问)功能的高速网络、支持硬件事务内存和FPGA(Field Programmable Gate Array,现场可编程门阵列)加速的CPU处理器等。以计算能力为例,CPU/GPU/FPGA不断延续摩尔定律。自2005年Intel首次提供了针对CPU的硬件辅助VT-x(Virtualization Technology for x86,x86虚拟化技术)后,硬件辅助虚拟化成为主流的“一虚多”虚拟化方法。目前,基于硬件辅助的虚拟化方法在CPU、内存和网络等传统的硬件资源上获得了成功,特别是CPU和内存虚拟化性能已经接近物理性能。新型异构设备(如FPGA、GPU)逐步成为大数据和人工智能等专用计算系统的核心要素,是算力输出的重要甚至主要部分。但这些新型设备要么没有虚拟化,要么处于虚拟化的早期水平,导致云无法享受“新硬件红利”。直到2014年,各大厂商才提出了以Intel gVirt、GPUvm为代表的硬件辅助虚拟化方案,但该方案远未成熟。
下面以GPU为典型代表介绍新型硬件虚拟化的发展历史。
现代GPU的功能已经从原来的图形图像计算扩展到了视频编解码、高性能计算,甚至是GPGPU(General-Purpose Graphics Processing Unit,通用图形处理单元)。但GPU这类重要资源虚拟化的高性能、可扩展性和可用性相对于CPU仍处于滞后的阶段,例如2014年Intel的GPU虚拟化解决方案gVirt中,单个物理GPU仅支持3个vGPU(Virtual GPU,虚拟GPU),而同年发布的Xen 4.4已支持512个vCPU(Virtual CPU,虚拟CPU)。直到2016年,亚马逊等各大云服务提供商才陆续推出了商业化的GPU实例。
传统GPU虚拟化通过API转发(API Forwarding)的方式将GPU操作由虚拟机发送到Hypervisor代理执行,该方法被大量主流虚拟化产品所采用来支持图形处理,但并非真正意义上的完整硬件虚拟化技术,其性能和可扩展性均无法满足GPGPU等应用(如机器学习)的需要。
GPU虚拟化的软件模拟采用类似于CPU虚拟化中二进制转换方法。但相对于CPU,GPU的特性复杂,不同的设备提供商之间的GPU规格区别很大,GPU的资源很难被拆分,模拟的效率低。因此,典型的QEMU软件仅模拟了VGA设备的基本功能,它通过一个半虚拟化的图像缓冲区加速特定的2D图像访问,不符合高效、共享的虚拟化要求。
GPU虚拟化的设备直通(Passthrough)方法将物理GPU指定给虚拟机独占访问。设备直通有时也称为设备透传技术,直接将物理设备,通常是PCI(Peripheral Component Interconnect,外设组件互连)设备,配置给虚拟机独占使用(其他虚拟机无法访问该物理设备,4.2.4节详细介绍)。与API转发提供的良好GPU共享能力相比,设备直通方法通过独占使用提供了优异的性能。例如,基于Intel的VT-d/GVT-d技术,通过翻译DMA(Direct Memory Access,直接内存访问)所访问内存地址的方法将GPU分配给一个虚拟机使用,能够达到与原生物理GPU相近的性能,但牺牲了共享特性。NVIDIA的Tesla GPU也提供了类似的虚拟化方案Grid,虚拟机可以通过硬件直通的方式直接访问物理GPU。
在GPU虚拟化方面,由于架构复杂,既要支持常规显卡,又要支持GPGPU,直到2014年才发表了硬件支持的GPU全虚拟化方案(Intel早在2005年已增加对CPU虚拟化的硬件支持),即Intel提出的产品级开源方案gVirt和学术界提出的方案GPUvm(均发表于USENIX ATC 2014)。gVirt是第一个针对Intel平台的GPU全虚拟化开源方案,为每个虚拟机都提供了一个虚拟的GPU,并且不需要更改虚拟机的原生驱动。此后,在高性能、可扩展和可用性三个重要方面提出了一系列改进(如gHyvi、gScale和gMig等),为GPU虚拟化的广泛应用打下了良好基础。
2)“多虚一”虚拟化
单台物理主机已经能够拥有超过数百个CPU核、数千个GPU核、TB级内存以及超过100Gbps的网络带宽的硬件环境,由此产生了在单机上构建巨大规模/巨型虚拟机的迫切需求。资源扩展主要有资源横向扩展(Scale out)和资源纵向扩展(Scale up)两种方式。虚拟化资源横向扩展的好处是弹性分配、资源灵活使用且利用率高,但编程模型复杂;纵向扩展的好处是编程模型简单,避免了由于分布式系统和数据分区产生的软件复杂性,但硬件昂贵、灵活性差。针对内存计算等大规模计算需求,是否可以综合利用资源横向和纵向扩展的优势?通过虚拟化技术,可以在虚拟化层面聚合资源,使底层资源对上层客户机操作系统透明。
不同于传统的“一虚多”方法,这种“多虚一”的跨物理节点虚拟化架构可以将计算资源、存储资源和I/O资源虚拟化,构建跨节点的虚拟化资源池,向上对客户机操作系统提供统一的硬件资源视图,并且无须修改客户机操作系统。目前典型的跨节点虚拟化产品有以色列公司的ScaleMP和美国公司的TidalScale。其中TidalScale提出了一种软件定义服务器,通过超内核构建虚拟资源池,将主板上所有的DRAM(Dynamic Random Access Memory,动态随机存取存储器)内存抽象为虚拟化的L4缓存,并且引入了虚拟主板提供跨节点的虚拟设备连接,通过虚拟通用处理器、虚拟内存和虚拟网络构建虚拟资源池,并且资源可以迁移,用户可以灵活使用资源。通过复杂的缓存一致性算法和缓存管理算法,有效提升了性能。在一个包含1亿行、100列的数据库和128GB内存的服务器上,由于所需内存容量大于单个服务器硬件的内存容量,导致分页(Paging)频繁发生,以至于一个应用程序需要花费7小时才能完成MySQL的三次查询作业。这个现象称为“内存悬崖(Memory Cliff)”,即由于应用所需内存超过服务器内存导致性能急剧下降。而该查询运行在采用两个96GB内存节点组成TidalScale服务器上只需要7分钟,性能提升60倍[6]。
但ScaleMP和TidalScale都基于特定硬件和定制化闭源Type Ⅰ虚拟化平台(Type Ⅰ和Type Ⅱ虚拟化的区别详见1.3节)。Type Ⅰ虚拟化在裸机上运行Hypervisor,然后加载客户机操作系统,技术生态和应用范围受限制,无法和主流的Type Ⅱ开源虚拟化系统KVM/QEMU兼容。不同于Type Ⅰ虚拟化,Type Ⅱ虚拟化是在宿主机操作系统上运行Hypervisor,然后加载客户机操作系统,是目前主流的虚拟化方法,如KVM/QEMU被全球最大的亚马逊云服务和国内最大的阿里云等采用。
基于KVM/QEMU,GiantVM架构围绕高速网络RDMA技术实现虚拟化层面的硬件聚合和抽象,是目前首个开源的Type Ⅱ“多虚一”架构[7]。GiantVM以Libvirt为客户虚拟机上层接口,分布式QEMU提供跨节点虚拟机抽象,KVM为下层物理机提供管理接口,基于RDMA提供低延迟DSM(Distributed Shared Memory,分布式共享内存)。目前GiantVM可以将八台服务器虚拟成一台虚拟机,支持的客户机操作系统有Linux和瑞士的苏黎世联邦理工学院(ETH)Timothy Roscoe教授等提出的多内核操作系统Barrelfish[8]。关于GiantVM的相关实现技术,将在后续相关章节进行介绍。
由于跨节点通信一般为亚微秒级,与常规内存访问有数量级差距(纳秒级),虚拟化聚合“多虚一”的技术挑战是由于分布式共享内存同步需要跨节点通信,协议同步开销是性能损失的主要来源。传统方法在DSM同步中引入了普林斯顿大学李凯教授等提出的基于顺序一致性(Sequential Consistency)的IVY[9]协议,该协议的编程模型简单,但严格同步性能开销大。如何进一步降低DSM引入的“多虚一”性能开销是目前“多虚一”技术面临的重要技术挑战。
3)轻量级容器虚拟化
容器虚拟化技术最早可以追溯到1979年UNIX V7引入的chroot(change root)系统调用,通过将一个进程及其子进程的根目录(root目录)改变到原文件系统中的不同位置(虚拟根目录),使得这些进程只能访问该虚拟根目录下的文件和子目录。因此chroot为每个进程提供了相互隔离的虚拟文件系统(称为chroot Jail),被认为是轻量级进程隔离方法的雏形,标志着容器虚拟化的开始。
2000年发布的FreeBSD Jails比chroot提供了更完善的进程级容器(称为Jail)运行环境。每个Jail容器拥有各自的文件系统(基于chroot,并修正了传统chroot的安全漏洞)和独立的IP(Internet Protocol,网际协议)地址,对进程间通信也加以限制。因此,Jail容器中进程无法访问Jail之外的文件、进程和网络。此后,还发布了与FreeBSD Jails类似的进程隔离技术,如2001年的Linux VServer、2004年的Solaris Containers和2005年的Open VZ。
2006年谷歌公司发布了进程容器(Process Containers),提供了一系列进程级资源(包括CPU、内存和I/O资源)隔离技术,后来改名为控制组(Cgroups),并被合入Linux内核2.6.24。Cgroups技术沿用至今,也是目前的核心容器技术之一。
2008年Linux社区整合Cgroups和命名空间(Namespace),提出了完整的容器隔离方案LXC(Linux Containers,Linux容器)。LXC通过Cgroups隔离各类进程且同时控制进程的资源占用,并通过Namespace使每个进程组有独立的进程标识PID、用户标识、进程间通信IPC和网络空间,两者构成了完整的进程级隔离环境。容器之所以被称为轻量级虚拟化技术,是因为LXC基于同一个宿主机操作系统,仅在操作系统层次通过软件隔离出类似虚拟机的效果(“欺骗”进程,使其认为自身运行在不同机器上),不需要虚拟整个ISA(“欺骗”操作系统,使其认为自身运行在物理机上)。因此容器虚拟化的缺点是只支持相同宿主机操作系统上的隔离,而系统虚拟化提供异构客户机操作系统的隔离,两者提供了不同层次的隔离,互为补充。
2013年dotCloud公司(后更名为Docker)发布了基于LXC的开源容器引擎Docker,引入了分层镜像(Image)的概念,基于只读的文件系统提供容器运行时所需的程序、库和环境配置等,容器则作为一个轻量级应用沙箱,提供应用所需的Linux动态运行环境(包括进程空间、用户空间和网络空间等)。Docker引擎基于容器运行和管理各个用户态应用实例。Docker通过组合只读的静态镜像和可写的动态容器,部署方便且动态隔离,提供一整套容器的创建、注册、部署和管理的完整工具集。因此Docker问世后便迅速普及,成为容器技术的代名词。
2014年6月谷歌公司开源了基于容器的集群管理平台Kubernetes(10)(简称K8S,名字来源于希腊语“舵手”)。Kubernetes是基于谷歌内部使用的大规模集群管理系统Borg[10]实现的,其核心功能是自动化管理容器,解决大规模容器的编排、管理和调度问题。Kubernetes现已成为容器编排领域的事实标准,得到了广泛的应用。
此外,随着云原生(Cloud Native)和无服务器(Serverless)架构的日益成熟,更细粒度的FaaS(Function as a Service,函数即服务)将迎来更大的发展。虚拟机、容器和云函数作为资源抽象的不同层次,也会互为补充、相得益彰。