linux操作系统:虚拟机实现原理

linux很强大,inux 服务器也随之变得越来越强大了。无论是计算、网络、存储,都越来越牛。例如,内存动不动就是百 G 内存,网络设备一个端口的带宽就能有几十 G 甚至上百 G,存储在数据中心至少是 PB 级别的。但是也有其坏处:

  • 资源大小不灵活:有时候我们不需要这么大规格的机器,可能只想尝试一下某些新业务,申请个4核8G的服务器试一下,但是不可能采购这么小规格的机器。无论每个项目需要多大规格的机器,公司统一采购就限制几种,全部是上面那种大规格的。
  • 资源申请不灵活:规格定死就定死吧,可是每次申请机器都要重新采购,周期很长。
  • 资源复用不灵活:反之我需要的资源不多,和别人共享一台机器把,这样不同的进程可能会冲突。另外就是其他人用过的机器,不知道上面做过哪些操作,有很多历史包袱,如果重新安装则代价太大。

为了解决这些问题,可以在物理机上创建虚拟机。每个虚拟机都有自己单独的操作系统、灵活的规格,一个命令就能启动起来。每次创建都是新的操作系统,很好的解决了上面不灵活的问题。

但是要使用虚拟机,还有一些问题需要解决一下。

我们知道,操作系统上的程序分为两种,一种是用户态的程序,比如work,Excel等,一种是内核态的程序,比如内核代码、驱动程序等。

为了区分内核态和用户态,CPU专门设置四个特权等级0、1、2、3来做这个事情。

当时写linux内核的时候,估计大牛们还不知道将来虚拟机会大放异彩。大牛们想,一共两级特权,一个内核态、一个用户态,却有四个等级,很奢侈、很丰富,于是就敞开了用。内核态运行在第0等级,用户态运行在第3等级,占了两头,中间的都不用,太不会过日子了。

大牛们在写linux内核的时候,如果用户态程序做事情,就将扳手掰到第 3 等级,一旦要申请使用更多的资源,就需要申请把扳手掰到第 0 等级,内核才能在高权限访问这些资源,申请完资源,返回到用户态,扳手再掰回去。

这个程序一直非常顺利的运行着,直到虚拟机出现了

三种虚拟化方式

如果你安装virtualBox桌面版,你可以用这个虚拟机软件创建虚拟机,在虚拟机里面按照一个linux,外面的操作吸引也可以是linux。VirtualBox 这个虚拟化软件,和你的 Excel 一样,都是在你的任务栏里面并排放着,是一个普通的应用。

当你进入虚拟机的时候,虚拟机里面的 Excel 也是一个普通的应用。

这个时候麻烦的事情出现了,当你设身处地地站在虚拟机的内核角度,去思考一下人生,你就会出现困惑了,会想,我到底是啥?

在硬件上的操作系统来看,我是一个普通的应用,只能运行在用户态。可是大牛们“生“我的时候,我的每一行代码都告诉我,我是个内核啊,应该运行在内核态。当虚拟机里面的 Excel 要访问网络的时候,向我请求,我的代码就要努力地去操作网卡。尽管我努力,但是我做不到啊,我没有权限!

我分裂了……

怎么办呢?虚拟化层,也就是 Virtualbox 会帮你解决这个问题,它有三种虚拟化的方式。

我们先来看第一种方式,完全虚拟化(Full virtualization)。其实说白了,这是一种“骗人”的方式。虚拟化软件会模拟假的 CPU、内存、网络、硬盘给到我,让我自我感觉良好,感觉自己终于又像个内核了。

但是,真正的工作模式其实是下面这样的。

虚拟机内核说:我要在 CPU 上跑一个指令!
虚拟化软件说:没问题,你是内核嘛,可以跑!
虚拟化软件转过头去找物理机内核说:报告,我管理的虚拟机里面的一个要执行一个 CPU 指令,帮忙来一小段时间空闲的 CPU 时间,让我代它跑个指令。
物理机内核说:你等着,另一个跑着呢。(过了一会儿)它跑完了,该你了。
虚拟化软件说:我代它跑,终于跑完了,出来结果了。
虚拟化软件转头给虚拟机内核说:哥们儿,跑完了,结果是这个。我说你是内核吧,绝对有权限,没问题,下次跑指令找我啊!
虚拟机内核说:看来我真的是内核呢,可是,哥,好像这点儿指令跑得有点慢啊!
虚拟化软件说:这就不错啦,好几个排着队跑呢!

内存的申请模式是下面这样的。

虚拟机内核说:我启动需要 4G 内存,我好分给我上面的应用。
虚拟化软件说:没问题,才 4G,你是内核嘛,我马上申请好。
虚拟化软件转头给物理机内核说:报告,我启动了一个虚拟机,需要 4G 内存,给我 4 个房间呗。
物理机内核:怎么又一个虚拟机啊!好吧,给你 90919293 四个房间。
虚拟化软件转头给虚拟机内核说:哥们,内存有了,0123 这个四个房间都是你的。你看,你是内核嘛,独占资源,从 0 编号的就是你的。
虚拟机内核说:看来我真的是内核啊,能从头开始用。那好,我就在房间 2 的第三个柜子里面放个东西吧!
虚拟化软件说:要放东西啊,没问题。但是,它心里想:我查查看,这个虚拟机是 90 号房间开头的,它要在房间 2 放东西,那就相当于在房间 92 放东西。
虚拟化软件转头给物理机内核说:报告,我上面的虚拟机要在 92 号房间的第三个柜子里面放个东西。

好了,说完了 CPU 和内存的例子,网络和硬盘就不细说了,情况也是类似的,都是虚拟化软件模拟一个给虚拟机内核看的,其实啥事儿都需要虚拟化软件转一遍。

这种方式一个坏处就是,慢,而且往往慢到不能忍受。

于是,虚拟化软件想,我能不能不当传话筒,要让虚拟机内核正视自己的身份。别说你是内核,你还真喘上了。你不是物理机,你是虚拟机!

但是,怎么解决权限等级问题呢?于是,Intel的VT-x和AMD的AMV-V从硬件层面帮上了忙。当初谁让你们这些写内核的大牛用等级这么奢侈,用完了 0,就是 3,也不省着点儿用,没办法,只好另起炉灶弄一个新的标志位,表示当前是在虚拟机状态下,还是在真正的物理机内核下。

对于虚拟机内核来讲,只要将标志位设为虚拟机状态,我们就可以直接在CPU上执行大部分的指令,不需要虚拟机软件在中间转述,除非遇到特别敏感的指令,才需要将标志位设为物理机内核态运行,这样大大提高了效率。

所以,安装虚拟机的时候,我们务必要将物理 CPU 的这个标志位打开。想知道是否打开,对于 Intel,你可以查看 grep “vmx” /proc/cpuinfo;对于 AMD,你可以查看 grep “svm” /proc/cpuinfo

这叫作硬件辅助虚拟化(Hardware-Assisted Virtualization)。

另外就是访问网络或者硬盘的时候,为了取得更高的性能,也需要让虚拟机内核加载特殊的驱动,也是让虚拟机内核从代码层面就重新定位自己的身份,不能像访问物理机一样访问网络或者硬盘,而是用一种特殊的模式。

我知道我不是物理机内核,我知道我是虚拟机,我没那么高的权限,我很可能和很多虚拟机共享物理资源,所以我要学会排队,我写硬盘其实写的是一个物理机上的文件,那我的写文件的缓存方式是不是可以变一下。我发送网络包,根本就不是发给真正的网络设备,而是给虚拟的设备,我可不可以直接在内存里面拷贝给它,等等等等。

一旦我知道我不是物理机内核,痛定思痛,只好重新认识自己,反而能找出很多方式来优化我的资源访问。

这叫作半虚拟化(Paravirtualization)。

对于桌面虚拟化软件,我们多采用 VirtualBox,如果使用服务器的虚拟化软件,则有另外的选型。

服务器上的虚拟化软件,多使用 qemu,其中关键字 emu,全称是 emulator,模拟器。所以,单纯使用 qemu,采用的是完全虚拟化的模式。

qemu 向 Guest OS 模拟 CPU,也模拟其他的硬件,GuestOS 认为自己和硬件直接打交道,其实是同 qemu 模拟出来的硬件打交道,qemu 会将这些指令转译给真正的硬件。由于所有的指令都要从 qemu 里面过一手,因而性能就会比较差。

在这里插入图片描述
按照上面的介绍,完全虚拟化是非常慢的,所以要使用硬件辅助虚拟化技术 Intel-VT,AMD-V,所以需要 CPU 硬件开启这个标志位,一般在 BIOS 里面设置。

当确认开始了标志位之后,通过 KVM,GuestOS 的 CPU 指令不用经过 Qemu 转译,直接运行,大大提高了速度。

所以,KVM 在内核里面需要有一个模块,来设置当前 CPU 是 Guest OS 在用,还是 Host OS 在用。

下面,我们来查看内核模块中是否含有 kvm, lsmod | grep kvm。

KVM 内核模块通过 /dev/kvm 暴露接口,用户态程序可以通过 ioctl 来访问这个接口。例如,你可以通过下面的流程编写程序。
在这里插入图片描述

Qemu 将 KVM 整合进来,将有关 CPU 指令的部分交由内核模块来做,就是 qemu-kvm (qemu-system-XXX)。

qemu 和 kvm 整合之后,CPU 的性能问题解决了。另外 Qemu 还会模拟其他的硬件,如网络和硬盘。同样,全虚拟化的方式也会影响这些设备的性能。

于是,qemu 采取半虚拟化的方式,让 Guest OS 加载特殊的驱动来做这件事情。

例如,网络需要加载 virtio_net,存储需要加载 virtio_blk,Guest 需要安装这些半虚拟化驱动,GuestOS 知道自己是虚拟机,所以数据会直接发送给半虚拟化设备,经过特殊处理(例如排队、缓存、批量处理等性能优化方式),最终发送给真正的硬件。这在一定程度上提高了性能。

至此,整个关系如下图所示。
在这里插入图片描述

总结

  • 虚拟化的本质是用 qemu 的软件模拟硬件,但是模拟方式比较慢,需要加速;
  • 虚拟化主要模拟 CPU、内存、网络、存储,分别有不同的加速办法;
  • CPU 和内存主要使用硬件辅助虚拟化进行加速,需要配备特殊的硬件才能工作;
  • 网络和存储主要使用特殊的半虚拟化驱动加速,需要加载特殊的驱动程序。

猜你喜欢

转载自blog.csdn.net/zhizhengguan/article/details/121708406