虚拟化技术大概在上世纪90年代末就已经出现了,这个技术初始就是为了提高计算机的利用率,降低闲置率,并为上层系统搭建提供灵活性。发展到现在,虚拟化技术已经五花八门,云计算这个当下最新最潮的IT技术离不开虚拟化能力。

我不懂虚拟化技术,闲杂时间看了些概念,特记录于此,有不对的地方我会及时更正。先聊聊CPU的虚拟化,因为存储虚拟化、内存虚拟化等技术都离不开虚拟CPU,这是最核心的能力。

预备知识: Ring分层:X86架构下的系统,CPU的指令存在特权等级。分为Ring0,Ring1,Ring2,Ring3,内核层关键指令拥有最高级别的Ring0,硬件驱动相关指令运行在Ring1,而用户态进程的指令运行在Ring3。

  • 特权指令 指的是控制系统关键资源的,拥有最高权限的指令。比如I/O指令,修改寄存器指令等。
  • 敏感指令 引入虚拟化后,Guest OS就不能运行在Ring 0上。因此,原本需要在最高级别下执行的指令就不能够直接执行,而是交由VMM处理执行。这部分指令称为敏感指令。

典型的虚拟化技术采用“特权-解除”和“陷入捕获”的思想。特权解除什么意思呢,即不让GuesetOS拥有Ring0的特权,让Hypervisor即VMM掌握Ring0,即有权利控制系统所有资源,GuestOS的普通指令可以直接运行,而特权指令借由VMM来处理;而陷入捕获就是说,当cpu在执行某条指令时,如果不在内核态,就会触发“陷入”,就是抛出一个异常,让系统软件去处理,VMM的设计就是利用了这个特性。

在X86架构下,特权指令就一定是敏感指令,而敏感指令却并非全部是特权指令。X86下还有一个问题,就是那些希望让VMM进行陷入捕获,从而得到处理的命令不属于特权指令,也就是说CPU无法发生陷入。这样一来,典型的虚拟化技术就不能完全适用于X86架构的虚拟化了。所以当前虚拟化技术原理的区别主要就是处理这个问题上的区别了。

当前虚拟化模型大致可分为下列三种:

  • 纯虚拟化(Full) 所谓纯虚拟化,即是让GuestOS不感知自己当前是被虚拟出来的,是依托在VMM上的。其核心思想是使用类似转译的方法,所有敏感指令都会被陷入捕获,并且针对以上提到问题中的那些特殊指令,做一层转译,翻译成特权指令,这样就能触发陷入从而得到处理。优点是虚拟能力强,无需对GuestOS做任何修改;缺点是任何指令都要大量陷入,性能较差。

  • 半虚拟化(Para) 所谓半虚拟化,就是让GuestOS知道自己是虚拟机,即内核被修改。其核心思想就是改造核心逻辑,对GuestOS内部发送的指令都做了层封装,即使用“超调用”(HyperCall)来直接操作VMM,调用VMM的命令来处理指令。优点是使用超调用,减少频繁的陷入,性能较好;缺点也很明显,即是需要改造GuestOS,适用性不高。所以现在半虚拟化技术没有成为主流技术。

  • 芯片辅助虚拟化 所谓芯片辅助虚拟化,也就是硬件辅助的虚拟化。这种技术提出了一种新的解决方案,以Xen技术做为代表。其核心思想是切分CPU指令为根模式和非根模式,每个模式都具有Ring0等级的特权。即是让VMM运行在根模式的Ring0下,让GuestOS和GuestOS承载的APP运行在非根模式的Ring0和Ring3下。而其中VMM承担了非根模式到根模式Ring0的转换,这个由硬件来完成,即芯片支持,比如Intel的Intel-VT技术。这种类型的虚拟化技术已经成为主流,因为优势太明显,即不用修改GuestOS,也不影响性能。

所谓虚拟CPU,即vCPU,其实不是一个真实存在的硬件模拟,这点跟内存虚拟化,I/O虚拟化不同,vCPU是一个抽象、逻辑上的概念。说白了就是VMM层代替完成了CPU的活儿。

寄存器的虚拟原理,假设GuestOS要做个计算操作,让值保持在VR0寄存器上,然后CPU处理结果放在VR1上,那么VMM就会在内存中开辟一个空间,分别用来模拟VR0和VR1。VMM收到VR0上的值后,会调用指令发送到物理CPU上,等到物理CPU计算后返回,又把结果放在VR1上,最终返回给GuestOS,那么从GuestOS上看,实际上就等于使用了真实的物理CPU。