侧边栏壁纸
博主头像
landery博主等级

行李箱里装不下我想去的远方

  • 累计撰写 45 篇文章
  • 累计创建 26 个标签
  • 累计收到 6 条评论

目 录CONTENT

文章目录

云计算_05_虚拟化_KVM虚拟化技术

landery
2022-04-25 / 0 评论 / 0 点赞 / 88 阅读 / 2,533 字 / 正在检测是否收录...
温馨提示:
本文最后更新于 2022-05-10,若内容或图片失效,请留言反馈。部分素材来自网络,若不小心影响到您的利益,请联系我们删除。

1 KVM虚拟化架构

1.1 主流虚拟化架构对比

2 KVM CPU虚拟化

作为VMM,KVM分为两部分,分别是运行于Kernel模式的KVM内核模块和运行于User模式的Qemu模块。这里的Kernel模式和User模式,实际上指的是VMX根模式下的特权级0和特权级3。另外,KVM将虚拟机所在的运行模式称为Guest模式。所谓Guest模式,实际上指的是VMX的非根模式。
kvm_vmx_intel_oenhan

利用VT-x技术的支持,KVM中的每个虚拟机可具有多个虚拟处理器VCPU,每个VCPU对应一个Qemu线程,VCPU的创建、初始化、运行以及退出处理都在Qemu线程上下文中进行,需要Kernel、User和Guest三种模式相互配合,其工作模型如图2.1所示。Qemu线程与KVM内核模块间以ioctl的方式进行交互,而KVM内核模块与客户软件之间通过VM Exit和VM entry操作进行切换。

Qemu线程以ioctl的方式指示KVM内核模块进行VCPU的创建和初始化等操作,主要指VMM创建VCPU运行所需的各种数据结构并初始化。其中很重要的一个数据结构就是VMCS,其初始化配置见附2。

初始化工作完成之后,Qemu线程以ioctl的方式向KVM内核模块发出运行VCPU的指示,后者执行VM entry操作,将处理器由kernel模式切换到Guest模式,中止宿主机软件,转而运行客户软件。注意,宿主机软件被中止时,正处于Qemu线程上下文,且正在执行ioctl系统调用的kernel模式处理程序。客户软件在运行过程中,如发生异常或外部中断等事件,或执行I/O操作,可能导致VM exit,将处理器状态由Guest模式切换回Kernel模式。KVM内核模块检查发生VM exit的原因,如果VM exit由于I/O操作导致,则执行系统调用返回操作,将I/O操作交给处于User模式的Qemu线程来处理,Qemu线程在处理完I/O操作后再次执行ioctl,指示KVM切换处理器到Guest模式,恢复客户软件的运行;如果VM exit由于其它原因导致,则由KVM内核模块负责处理,并在处理后切换处理器到Guest模式,恢复客户机的运行。

3 Qemu/KVM

image-1652162290321
可以看到,对于宿主机来说,一个虚拟机对应一个Qemu进程,Qemu的作用可以理解为,为Qemu内部的虚拟机VM,创建内存,创建vcpu,或者可以换个角度来说,是其内部的VM使用了Qemu进程映射的内存,但是Qemu实际映射的内存,其实是由KVM来实现的,Qemu只是调用了KVM内核接口来分配内存、vcpu等操作,这里可以理解为我们普通的进程申请内存空间,都得通过linux内核给的接口来实现内存申请是一样的。
而对于宿主机来说,Qemu只是一个普通的进程,宿主机并不把它认为是Guest OS。

而且Qemu对于KVM来说,主要是用来做IO的虚拟化,简单地说就是IO的操作模拟。
加入Qemu进程中的VM发生了VM-Exit事件,会进入Root模式的KVM中,KVM会分析引起事件的原因是什么?如果是IO事件,这里就分为几种不同的方式。之前我们已经提到过Qemu/KVM实现的IO虚拟化是有全虚拟化和半虚拟化两种方式的。

3.1 IO全虚拟化

全虚拟化我们已经讲过,他是使用软件模拟的方式。这种方式,当VM发生IO事件时,如果这些操作发生了VM-Exit,那么在KVM判断过后,发现是IO事件,会将这个IO请求交给Qemu进程处理,例如发网络数据包、输出字符等。

于是qemu进程将此操作代替Guest完成后并执行相应的“回调”,通过ioctl调用告诉KVM IO操作已完成,进入VM继续运行。这个过程就涉及到VM-Exit和VM-Entry操作,会造成较大的开销。

image-1652164950883

当然在这个图中,不能完全的描述IO过程,例如如果是IO事件,KVM将事件交给Qemu进程处理后,就类似我们打印机IO,CPU并不会等待IO执行完成,而是采用了DMA的方式,在IO处理的期间,Qemu中的虚拟机也是可以继续运行的。当IO操作结束后,通过设置vcpu或者cpu中断告知VM IO事件已经处理完成,vcpu中断也是通过设置相应的中断寄存器实现的。

3.2 IO半虚拟化

前面文章我们也说过了,IO半虚拟化。qemu/kvm的半虚拟化实现,是通过virtio 驱动来实现的,通过了共享内存的方式来实现优化。
image-1652165156131
上图是KVM/Qemu Virtio 网络虚拟化的一个图,相较于之前的全虚拟化,Virtio通过在Guest的Driver层引入了两个队列和相应的队列就绪描述符与qemu-kvm层Virtio Backend进行通信,并用文件描述符来替代之前的中断。

Virtio front-end与后端之间通过Vring buffer交互,在qemu中,使用事件循环机制来描述buffer的状态,这样当buffer中有数据的时候,qemu-kvm会监听到eventfd的事件就绪,于是就可以读取数据后发送到tap设备,当有数据从tap设备过来的时候,qemu将数据写入到buffer,并设置eventfd,这样front-end监听到事件就绪后从buffer中读取数据。

可以看到,这种方式不像全虚拟化方式,频繁发生VM-Exit和VM-Entry事件,减少了处理器的开销。但是这种方式依然存在问题,可以看到存在多次内存拷贝,对于网络io来说,效果不怎么好,于是vhost-net出现了。这个我们简单说一下,有时间再细说。

image-1652165812364

vhost-net 绕过了 QEMU 直接在Guest的front-end和backend之间通信,减少了数据的拷贝,特别是减少了用户态到内核态的拷贝。性能得到大大加强,就吞吐量来说,vhost-net基本能够跑满一台物理机的带宽。vhost-net需要内核支持,Redhat 6.1 后开始支持,默认状态下是开启的。

参考文献

0

评论区