All problems in computer science can be solved by another level of indirection.

前言

今天把《系统虚拟化: 原理与实现》草草看完,略过了类虚拟化实现、虚拟化性能测试的内容。

本书作者是英特尔开源软件技术中心,在2009年出版。现在是2024年,虚拟化技术已经很成熟了,但是这本书作为入门读物还是挺不错的。其次本由书复旦大学撰稿,可以说是原汁原味了。

其实很多虚拟化的相关的东西我们都不陌生了(比如 docker),看书的过程看到很多熟悉的影子,读起来也不是很费劲。这里随便记一记阅读过程中想到的(非科普)

开头简单介绍了x86架构的一些硬件概念,这些在学操作系统的时候一般也会提及。接着提出虚拟机监控器(Virtual Machine Monitor,简称VMM)的概念,VMM可以简单理解为虚拟机程序(比如VMware Workstation),这个概念始终贯穿全书。

虚拟化分类:

按模型分类

hypervisor模型、宿主模型、混合模型。

  1. hypervisor模型: VMware ESXi, 企业版虚拟机软件
  2. 混合模型: 云服务器厂商常用的KVM是混合模型, KVM一般和QEMU混合
  3. 宿主模型: 我们在 PC 经常使用的VMware Workstation属于桌面版虚拟机软件,是宿主模型。

P.S. KVMqemu都是开源的。

按实现分类

  1. 基于软件的完全虚拟化: 我们一般叫模拟器,用代码模拟指令,如QEMUNEMU,之前和任天堂打官司的Yuzu柚子模拟器
  2. 硬件辅助的完全虚拟化: 直接用硬件跑指令, Intel VT-x/VT-d
  3. 类虚拟化: 直接用硬件跑指令,但是要改客户机操作系统部分代码

P.S. 如果你从未在BIOS里开启过VT-x, 此时又想用虚拟机,你会发现开不了。

当我们虚拟化的时候,我们在谈论什么

虚拟化到底要做什么呢,其实就是下面三件事

  1. CPU虚拟化: 模拟物理CPU,主要是捕获并模拟敏感指令
  2. 内存虚拟化: 模拟物理内存,让客户机能正确内存寻址
  3. 硬件虚拟化: 模拟物理设备,让客户机能使用 DMA、中断等

看完了基于软件的实现,感觉原理很复杂。核心思想就是引入VMM, 让VMM作为一个管理员参与到整个计算过程。在没有硬件虚拟化支持的年代,各个公司开发了五花八门的虚拟化的技术,但是还是会有很多漏洞存在,补了一个坑就有新的坑。

直到硬件虚拟化出现,可以明显感觉到,虚拟化这个问题简单了起来。果然软件的各种trick,硬件一条指令就优化了。

所以有时候一个方案设计太复杂,我们要停下来想一想,是不是走了弯路。

硬件虚拟化主要是引入了根模式/非根模式,这两种模式和系统的运行级别(ring)是正交的。VMM 工作在根模式,客户机运行在非根模式,客户机可以处于ring0也可以处于ring3。至于为什么要设计这个模式?这种模式有点像软件中断,软件中断发生的时候,会跳转到中断处理函数,中断处理函数需要把用户态的上下文压栈,以便后续恢复。非根模式下,运行到敏感指令时,CPU会中断并把上下文保存进VCPU(一个内存结构)中,然后进入VMM,当VMM逻辑运行完毕后,又会从VCPU恢复上下文,继续运行虚拟机。我理解这种模式就是更底层的软件中断。

当然,软件虚拟化现在也没有消失, 比如你就可以在PC玩到塞尔达🤣,QEMU也是KVM的好伙伴。一种新技术的出现总是为了改善已有问题。如果大家没有虚拟化的强烈需求,硬件公司也不会去支持虚拟化。

Docker

最后说说dockerdocker是在虚拟化什么呢。

docker虚拟化的是操作系统级别的资源,比如能用多少cpu、用多少内存。同一个操作系统上的两个容器,是共享同一个操作系统的。举个例子,两个容器中的同一进程,页表的内容肯定是不一样的。而如果你的docker镜像用到了内核某个版本的特性,那么启动容器的时候就要注意宿主机的内核版本。

虚拟机还包括了硬件资源的虚拟化。同一台机器上的两个虚拟机实例,每个实例都要运行一个操作系统。

所以我们常说docker是轻量的虚拟化。启动一个docker镜像比启动一个虚拟机快得多。