KVM是必须使用硬件虚拟化辅助技术(如Intel VT-x、AMD-V)的Hypervisor,在cpu运行效率方面有硬件支持、其效率是比较高的;前端
在有Intel EPT特性支持的平台上,内存虚拟化的效率也较高。后端
不过,KVM在I/O虚拟化方面,传统的方式是使用QEMU纯软件的方式来模拟I/O设备,其效率不好。(性能和兼容性的博弈)网络
QEMU模拟过程socket
在使用QEMU模块I/O的状况下,当客户机中的设备驱动程序(Device Driver)发起I/O操做请求之时,KVM模块(Module)中的I/O操做捕获代码会拦截I/O请求,而后在通过处理后将本次I/O请求。而后通过处理后将本次I/O请求的信息存放到I/O共享页(sharing page),并通知用户空间的QEMU程序。Qemu模拟程序获取I/O操做的具体信息以后,交由硬件模拟代码(EmulationCode)来模拟出本次的I/O操做,完成以后,将结果放回到I/O 共享页,并通知KVM模块中的I/O操做捕获代码。最后,由KVM模块中的捕获代码读取I/O共享页中的操做结果,并把结果返回到客户机中。固然,在这个操做过程当中客户机做为一个Qemu进程在等待I/O是也可能被阻塞。另外,当客户机经过DMA(Direct Memory Access)访问大块I/O之时,QEMU模拟程序将不会把操做结果放到I/O共享页中,而是经过内存映射的方式将结果直接写到客户机内存中区,而后经过KVM模块告诉客户机DMA操做已经完成。性能
virtio I/O半虚拟化磁盘操作系统
前端驱动(frondend,如virtio-blk、virtio-net)是在客户机中存在的驱动程序模块,然后端处理程序(backend)是在QEMU中实现的。命令行
在先后端定义了两层来支持客户机与QEMU之间的通讯。队列
virtio层,在概念上,将前端驱动程序附加到后端程序。一个前端驱动程序可使用0个或多个队列,具体数量取决于需求。(virtio-net 2个队列,virtio-blk一个队列)进程
虚拟队列实际上被实现为跨越客户机操做系统和Hypervisor的衔接点,但该衔接点能够经过任意方式实现。内存
virtio-ring实现了环形缓冲区(ring buffer),用于保存前端驱动和后端处理程序执行的信息,而且该环形缓冲区能够一次性保存前端驱动的屡次请求,而且交由后端驱动去批量处理,最后实际调用宿主机中设备驱动实现物理上的I/O操做,这样作就能够根据约定实现批量处理而不是客户机中每次I/O请求都须要处理一次,从而提升客户机与Hypervisor信息交换的效率。
virtio、virtio_ring、virtio_pci等驱动程序提供了对virtio API的基本支持,是使用任何virtio前端驱动都必须使用的,并且他们的加载还有必定的顺序,应该按照virtio、virtio_ring、virtio_pci的顺序加载,而virtio_net、virtio_blk这样的驱动能够根据实际须要进行选择性的编译和加载。
virtio ballooning
气球中的内存时能够供宿主机使用的(但不能被客户机访问或使用),因此,当客户机内存紧张,空余内存很少的时候,能够请求客户机回收利用已分配给客户机的部份内存,客户机就会释放其空下内存,此时若客户机空闲内存不足,可能还会回收部分使用中的内存,可能会将部份内存换出到客户机的交换分区(swap)中,从而是内存气球充气膨胀,进而是宿主机回收气球中的内存用于其余进程。反之,当客户机内存不足时,也可让客户机的内存气球压缩,释放出内存气球中的部份内存,让客户机使用更多的内存。(真绕!)
KVM中ballooning的工做过程主要有以下步骤:
1) Hypervisor(即KVM)发送请求到客户机操做系统让其归还必定数量的内存给Hypervisor
2) 客户机操做系统中的virtio_balloon驱动接收到Hypervisor的请求。
3) virtio_balloon驱动使客户机的内存气球膨胀,气球中的内存就不能被客户机访问。若是此时客户机中的内存剩余很少,而且不能让内存气球膨胀到足够大以知足Hypervisor的请求,那么virtio_balloon驱动也会尽量地提供内存使气球膨胀,尽可能去知足Hypervisor的请求中的内存数量(即便不必定能彻底知足)。
4) 客户机操做系统归还气球中的内存给Hypervisor
5) Hypervisor能够将气球中得来的内存分配到任何须要的地方
6) 即便从气球中获得的内存没有处于使用中,Hypervisor也能够将内存返还到客户机中,这个过程为:Hypervisor发请求到客户机的virtio_balloon驱动;这个请求是客户机操做系统压缩内存气球;在气球中的内存被释放出来,从新由客户机访问和使用。
vhost_net后端驱动
virtio在宿主机中的后端处理程序(backend)通常是由用户空间的QEMU提供的,然而,若是对于网络IO请求的后端处理可以在内核空间开完成,则效率会更高提升网络吞吐量和减小网络延迟。
vhost-net的驱动模块,做为一个内核级别的后端处理驱动,将virtio-net的后端处理任务放到内核空间中执行,从而提升效率。
“使用网桥模式”
-net tap,[,vnet_hdr=on|off][,vhost=on|off][,vhostfd=h][,vhostforce=on|off]
通常来讲,使用vhost-net做为后端处理程序能够提升网络的性能。不过,对于一些使用vhost-net做为后端的网络负载类型,可能使其性能不升反降。特别是从宿主机到其客户机之间的UDP流量,若是客户及处理接受数据的速度比宿主机发送的速度要慢,这是就容易出现性能降低。在这种状况下,使用vhost-net将会是UDPsocket的接受缓冲区更快的溢出,从而致使更多的数据包丢失。所以在这种状况下不使用vhost-net,让传输速度稍微慢一点,反而会提升总体的性能。
使用qemu-kvm命令行时,加上“vhost=off”
<interface type="network">
<model type="virtio"/>
<driver name="qemu"/>
</interface>
virtio_blk 驱动使用virito API为客户机提供了一个高效访问块设备I/O的方法。
在QEMU/KVM中对块设备使用virito,须要在两方面进行配置:客户机中的前端驱动模块virito_blk和宿主机中的QEMU提供后端处理程序。