斯坦福大学Mendel Rosenblum教授带领课题组研发了分布式操作系统Hive、机器模拟器SimOS和虚拟机监控器DISCO [4] 。基于这些技术积累,Mendel Rosenblum作为共同创始人在1998年创建了VMware公司,也是硅谷产学研结合的典型代表。由于当时x86架构在硬件上还不支持虚拟化,因此VMware公司采用动态二进制翻译技术与直接执行相结合的全虚拟化技术来优化性能,其虚拟机性能达到物理机的80%以上,CPU密集型的应用性能损失仅为3%~5%。具体而言,虚拟机用户态代码可直接运行(包括虚拟8086模式),虚拟机内核态代码基于动态二进制翻译执行。虽然动态二进制翻译增加了开销,但保证了敏感指令在Hypervisor监控下执行,符合1.3.2节描述的波佩克与戈德堡虚拟化需求中第一条准则(资源控制),弥补了x86架构的虚拟化漏洞。同时,由于用户态代码直接运行,性能比采用纯二进制翻译的系统大为提高,取得了x86架构中虚拟化技术的突破,也被视为第一个成功商业化的虚拟化x86架构。
VMware公司在1999年发布了桌面虚拟化产品Workstation 1.0(见图1-6(a)),可以在一台PC上以虚拟机的形式运行多个操作系统,属于Type Ⅱ全虚拟化技术,Windows客户机操作系统不加修改就可以运行。2002年VMware公司发布了其第一代Type I虚拟化产品ESX Server 1.5(见图1-6(b)),采用服务器整合(Server Consolidation)的方式,支持将多个服务器整合到较少的物理设备中。通常可以将10台虚拟机整合到1台物理机中(10∶1),这种“一虚多”的虚拟化方式大幅提升了服务器资源利用率,降低了数据中心的硬件成本,因此得到了广泛应用。
图1-6 VMware典型虚拟化系统
注:①管理物理硬件;②实现虚拟化功能。
2003年,剑桥大学Ian Pratt教授等发表了虚拟化领域的著名论文 Xen and the art of virtualization [5] ,提出了以半虚拟化技术为基础的代表性开源项目Xen。由于当时x86硬件还没有支持虚拟化,如果不修改客户机操作系统,采用二进制翻译或软件模拟的全虚拟化技术,则内存和I/O的虚拟化开销比较大。以内存虚拟化为例,VMware采用影子页表技术,系统同时存在影子页表和客户机操作系统的原有页表,两套页表通过缺页异常(Page Fault)保持同步,引入了大量的同步开销。而Xen通过修改客户机操作系统,不再保留两套页表(消除同步开销),同时通过超调用主动更新页表。这样既保证了客户机操作系统可以快速访问页表,并自由于每次更新都需要经过Xen的监控,又保证了Hypervisor对内存资源的资源控制。
Xen属于Type I Hypervisor(见图1-7),Hypervisor直接运行于物理硬件上,为了提供功能丰富的设备模型,提出了基于Dom0和DomU的资源管理架构。Dom0是修改后的特权Linux内核,专门提供访问物理设备的特权操作。并行存在多个DomU,但均没有访问物理设备的权限(设备直通除外),在客户机操作系统中提供了各种设备的前端驱动(Frontend Driver),取代了原有的设备驱动(需要修改客户机操作系统)。前端驱动通过I/O环(I/O Ring)和后端驱动(Backend Driver)共享数据(基于共享内存避免数据复制),前端驱动和后端驱动的控制面通过事件通道(Event Channel)进行通信,并通过授权表(Grant Table)控制各个虚拟机的访问权限(事件通道和授权表在图1-7中均未画出),后端驱动通过传统的设备驱动访问真实物理设备。
图1-7 Xen虚拟化架构
注:①DomU前端驱动将数据写入I/O环;②Dom0后端驱动读取I/O环数据;③后端驱动调用设备驱动;④设备驱动操作物理设备。
Xen在内存虚拟化和I/O虚拟化的性能提升方面取得了突破,不足之处是需要修改客户机操作系统内核。但随着Xen的广泛采用,基于前、后端驱动的架构也逐渐稳定,并形成了virtio标准化接口(如磁盘驱动virtio-blk、网络驱动virtio-net和GPU驱动virtio-GPU等),并被各主流操作系统(如Windows、Linux等)支持。因此,目前客户机操作系统已经原生支持virtio驱动接口,大部分情况下不再需要修改内核(但有时仍需要配置内核或安装驱动)。
VMware和Xen均是在x86硬件不支持虚拟化的情况下,采用软件的手段弥补虚拟化漏洞,随着Intel和AMD等厂商相继提出了硬件支持的虚拟化扩展,基于硬件辅助的虚拟化技术应运而生,并由于其性能优势,逐渐占据主流地位。KVM是Linux内核提供的开源Hypervisor,也是目前主流的虚拟化技术,拥有活跃的社区和论坛(KVM Forum)。KVM自内核2.6.20起被合并进Linux,作为Linux的一个内核模块,在Linux启动时被动态加载。KVM利用了硬件辅助虚拟化的特性,能够高效地实现CPU和内存的虚拟化。
事实上,KVM无法单独使用,因为它既不提供I/O设备的模拟,也不支持对整体虚拟机的状态进行管理。它向用户态程序(如QEMU)暴露特殊的设备文件/dev/kvm作为接口,允许用户态程序利用它来实现最为关键的CPU和内存虚拟化,但还缺少I/O虚拟化需要的设备模型(Device Model),而QEMU正好可以弥补这块功能。QEMU是开源的软件仿真器,它能够通过动态二进制翻译技术来实现CPU虚拟化,同时提供多种I/O设备的模拟,因此可以作为低速的Type Ⅱ虚拟机监视器系统进行工作。然而,二进制翻译这种模拟方法带来了巨大的性能开销,导致虚拟机运行缓慢。为此QEMU利用KVM暴露的/dev/kvm接口,以KVM作为“加速器”,从而极大地改善虚拟机的性能。
图1-8 KVM/QEMU架构
由于QEMU通常和KVM配合使用,因此整体称为QEMU/KVM,其架构如图1-8所示:QEMU通过打开设备文件/dev/kvm实现和KVM内核模块(kvm.ko)的交互。在创建虚拟机时,QEMU会根据用户配置完成创建vCPU线程、分配虚拟机内存、创建虚拟设备(包括磁盘、网卡等)等工作。在QEMU中,虚拟机的每个vCPU对应QEMU的一个线程,当QEMU完成了所有初始化工作后,会通过ioctl指令进入内核态的KVM模块中,由KVM模块通过虚拟机启动或恢复指令(如x86的VMLAUNCH或VMRESUME指令)切换到虚拟机运行,执行虚拟机代码。因此从宿主机操作系统的角度来看,虚拟机的每个CPU对应于系统中的一个线程,并且该线程受到QEMU的控制和管理。当CPU执行了特权指令或发生特定行为时,会触发虚拟机陷出事件退出到KVM,由KVM判断能否进行处理(比如对一个QEMU中模拟的I/O设备进行操作)。如果不能,则进一步返回到QEMU,由QEMU负责处理。
随着万物互联时代的到来,虚拟化技术进一步扩展到移动终端、嵌入式和车载设备等资源受限的平台,一系列嵌入式、轻量级虚拟化被提出来,例如QNX Hypervisor、Jailhouse、Xvisor、PikeOS和OKL4等。Linux基金会于2018年3月发布了开源的轻量级虚拟化平台ACRN 。ACRN针对实时性和安全性(针对车载场景)进行了适配优化,并为关键业务提供了安全性隔离。ACRN通过GVT-g支持GPU虚拟化,可以在车载场景下共享GPU。
ACRN是Type I虚拟化架构(见图1-9),类似于Xen的Dom0,采用特权级的服务操作系统(Service OS)来管理物理I/O设备的使用;类似于Xen的DomU,用户操作系统(User OS)由ACRN Hypervisor进行创建和管理。设备分为前、后端驱动,两者之间的数据共享(环/队列)通过标准的virtio接口进行访问。
图1-9 ACRN虚拟化架构
注:①前端驱动将数据写入I/O环;②后端驱动读取I/O环数据;③后端驱动调用设备驱动;④设备驱动操作物理设备。
表1-2总结了上述4种典型虚拟化系统的特点,它们是2000年之后有代表性的虚拟化系统,至今仍广泛使用。IBM、微软等主流操作系统厂商的虚拟化产品、亚马逊和阿里巴巴等主流云计算提供商的新型虚拟化技术(如亚马逊Nitro Hypervisor、阿里神龙服务器)和VirtualBox、Xvisor等开源系统也在市场中占据重要地位,限于篇幅,本书不做介绍 。
表1-2 典型虚拟化系统