参考:

    《kvm虚拟化技术 实战解析与原理》

    http://tec.5lulu.com/detail/107mwn4e6aaa684c1.html

    http://blog.chinaunix.net/xmlrpc.php?r=blog/article&uid=7934175&id=5679365


1.balloon技术简介:

    通常来说,要改变客户机的内存大小,我们需要关闭客户机,用qemu-system-x86_64重新分配。这个是很不方便的,于是balloon技术出现了。

    ballooning(气球)技术可以在客户机运行时动态地调整内存大小,而不需要关闭客户机。它是客户机的balloon driver通过virtio虚拟队列接口和宿主机协同工作来完成的。

    balloonDriver的作用在于它既可以膨胀自己使用内存大小也可以缩减内存使用量(可以缩减至几近于无),而且被balloon里面的内存客户机是不可以使用,balloonDriver本身并不直接管理balloon,它的扩容与缩减都是通过virtio队列由宿主机发送信号管理。宿主机可以把balloon的内存取消映射,拿来给其他客户机使用,也可以映射回去,并让balloon缩减,用来增加客户机内存。因为不能使用balloon里面的内存,所以当客户机的内存不足以满足自身应用时,它要么使用swap,要么开启OOM-killer选择性杀死一些进程。

     kvm virtio使用_第1张图片

    简单地说,类似于,你(客户机)会装货和卸货,但是至于要装还是卸,取决于你的老板(宿主机)。而这些货是干嘛的怎么用,那也是老板的事。你只有这么多货,不够用怎么办?要么造假(swap)要么不卖..

    ballooning工作过程主要有以下几步:

        (1)hypervisor发送请求到客户机操作系统让其缩减一定数量内存

        (2)客户机操作系统收到请求

        (3)客户机操作系统利用balloon驱动,缩减内存气球,并发送结果给hypervisor

        (4)vmm收到后,取消对balloon内存的映射,从而回收内存

        (5)vmm把这些内存自由分配到任何需要的地方

        (6)vmm也可以按相反的动作,扩充客户机内存

    事实上,kvm balloon技术并不完全是你想的那种动态分配,它是有内存上限的,它是这样子的:

        kvm hypervisor给客户机指定一个最大内存(MAXmemory),这个就是客户机最多能使用的内存大小

        客户机利用balloon驱动生成内存气球

        客户机当前能使用的真实内存(currentMemory)的值就是最大内存减去气球内存的结果

            currentMemory=MaxMemory-ballooning


2.ballooning的使用

    balloon需要客户机virtio驱动的支持,关于怎么安装驱动,上篇kvm virtio已有说明,这里不重复

    kvm 下balloon的启动,是利用-balloon virtio参数来指定,也可以使用-device来分配,如:

        -device virtio-balloon-pci,id=balloon0,bus=pci.0,addr=0x4

    我们可以用类似以下命令来启动客户机:

        qemu-system-x86_64  -m 4096 -smp 6 -balloon virtio  -net nic -net tap,script=/etc/qemu-ifup redhat6.qcow2 

    其中 -m 指明了MAXmemory的值,我们可以ctrl+alt+2切换到qemu monitor 模式利用info balloon 查看当前客户机可用的内存大小。利用balloon num设置balloon 可用内存大小,比如:

        (qemu) info balloon 

        balloon: actual=4096

        (qemu):balloon 2048 #这里虽然使用的是balloon命令,但是设置的值是currentMemory,而不是内存气球的值

    在linux下,可以利用free -m 等命令查看到内存明显变化。

    在windows下,可以利用任务管理器查看内存变化,与linux不同的是,windows下,改变currentMemory的值,任务管理器显示的内存总量并不会减少,而是把已使用量变高。比如:

        我们window的内存是4G,当前已经用掉213MB,如果此时我们balloon 2048,那么看到的内存总数依然是4G,但是已使用量会从213MB-->2303MB


    值得一提的是balloon设定的值不能超过-m指定的MAXMemory的值,一旦超过,则默认设置为MAXMemory的值


3.所谓的balloon内存过载使用:

    kvm下内存过载(能使用超过真实内存数量)使用有三种方式:

        swapping:就是把硬盘做成虚拟内存,这样能使用的内存就额外多了虚拟内存部分,大于真实内存

        page sharing:把各个进程访问到的相同数据块共享,这样内存只需要一份数据,从而各个进程所需要的内存数量加起来大于真实内存

        ballooning:利用每个主机不同时段负载不同这个特点实现,具体如下:

    我们知道,很多不同功能的主机不同时段负载不一样,比如提供OA高的主机白天负载比较高,提供娱乐的主机晚上负载比较高,所以一般平均负载不会太高。假设我们有A、B、C、D、E 5台客户机,工作在8G内存的宿主机上,他们的高峰期都需要2G的内存,而低峰期只需要512M不到的内存,假设A、B、C白天很忙,晚上很闲,而E、F白天很闲,晚上很忙,那么我们可以利用balloon技术,每台设置MAXMemory 2G,然后:

        白天:A、B、C的balloon设置为2G,EF 512M

        总共:2Gx3+512Mx2=7G

        晚上:A、B、C 各512M EF 1G

        总共:512Mx3+2Gx2=5632M

    这样,我们使用8G内存完成了看起来要10G才能运行的客户机,而且还有富余内存,很好地实现了内存过载使用


4.virtio_net的使用

1.查看kvm是否支持virtio

    [root@localhost kvm_vhost]# qemu-system-x86_64 -net nic,model=?

    qemu: Supported NIC models: ne2k_pci,i82551,i82557b,i82559er,rtl8139,e1000,pcnet,virtio


2.启动客户机,(客户机没驱动的参考上一篇,kvm virtio功能配置)

    qemu-system-x86_64  -m 4096 -smp 6 -balloon virtio  -net nic,model=virtio -net tap,script=/etc/qemu-ifup xp.qcow2 -usb -usbdevice tablet


3.宿主机中TSO和GSO的设置

    根据Redhat文档的接受,关闭GSO和TSO可以使半虚拟化网络驱动的性能更加优化,操作如下:

    (1)利用brctl show找出供客户机使用的真实网络接口,这里是em1

        [root@localhost ~]# brctl show

        bridge name    bridge         id               STP enabled    interfaces

        br08            000.02046d    871562                yes                 em1

                                                                                                tap0

    (2)ethtool -k eth0查看GSO和TSO状态

        [root@localhost ~]# ethtool  -k em1

        ...

        tcp-segmentation-offload: on#这个是TSO状态

        ...

        generic-segmentation-offload: on#这个是GSO状态

    (3)关闭gso和tso

        [root@localhost ~]# ethtool -K em1 gso off

        [root@localhost ~]# ethtool -K em1 tso off

        [root@localhost ~]# ethtool -k em1 

        ...

        tcp-segmentation-offload: off#这个是TSO状态

        ...

        generic-segmentation-offload: off#这个是GSO状态


5.使用vhost_net后端驱动

    前面所提到virtio在宿主机中的后端处理程序(backend)一般是由用户空间的qemu提供的,如果能把对网络i/o请求的后端处理能够在内核空间完成,那么效率会提高很多。在比较新的内核中有一个叫做“vhost-net”的驱动模块,它工作在内核中,利用它可以让virtio的后端处理程序的内容在内核中完成,从而提高效率。

    与vhost_net相关的选项是-net tap ,它的几个参数说明如下

        -net tap,[vnet_hdr=on|off][,vhost=on|off][,vhostfd=h][,vhostforce=on|off]

            vnet_hdr=on|off :是否打开tap设备的iff_vnet_hdr标识。这个标识表示允许发送或接受大数据包仅做部分的检查和校验,开启的话可以提高virtio_net驱动的吞吐量

            vhost=on|off :是否开启vhost-net这个内核空间的后端驱动,只对MIS-X中断的virtio客户机有效

            vhostforce=on|off :是否强制vhost作为非MIS-X中断的客户机后端处理程序

            vhostfs=h:设置去链接已经打开vhost的网络设备

     vhost_net需要宿主机的支持,所以可以lsmod |grep vhost_net查看有没有加载这个模块,没有的话modprobe vhost_net,如果内核不这个模块,那么需要重新编译内核

    使用vhost_net驱动的客户机启动命令如下:

        qemu-system-x86_64  /home/kvm_vhost/xp.qcow2  -net nic,model=virtio -net tap,vhost=on -usb -usbdevice tablet

    需要额外说明的是,如果使用libvirt时,xml配置指定的后端驱动名为qemu而不是vhost(这个我还没用过,存疑..没特殊声明的都是自己测试过的,请放心使用)


6.使用virtio_blk

    virtio_blk启动没什么好说的,利用-drive file=xx.img,if=virtio即可,命令如下:

        qemu-system-x86_64  -drive file=/home/kvm_vhost/redhat6.qcow2,if=virtio  -net nic,model=virtio -net tap,vhost=on  -curses

    有一点需要注意的是:使用virtio_blk后,设备会被识别为vda的形式,这可能会使原来fstab上的交换分区失效,比如:

        原来的fstab 交换分区配置:

            /dev/hda2 swap swap  defaults 0 0

        解决方法:

            改为: /dev/vda2 swap swap  defaults 0 0


7.kvm_clock配置

    之所以有这个配置是因为客户机的中断并非真正的中断,而是通过宿主机向客户机注入的虚拟中断,因此中断有可能不能立即传递给一个客户机的所有vcpu,这就可能导致中断需要的时间精确性得不到保证,这对一些应用来说是不行的。

    kvm通过kvm_clock向客户机提供精确的system time和wall time来解决这个问题,这个需要较新的硬件平台支持,默认是启动的。可以通过查看宿主机中的CPU信息的contabt_tsc标识来查看硬件是否支持,通过查看内核编译配置文件来了解是否支持kvm_clock

        grep constant_tsc /proc/cpuinfo

        grep -i paravirt_guest /boot/config-2.6.32-431.el6.x86_64

        grep -i kvm_clock /boot/config-2.6.32-431.el6.x86_64

    如果结果为y的话,就代表支持,默认qemu-system会让客户机使用kvm_clock作为时钟来源,可以在客户机中使用: dmesg |grep  -i kvm_clock 查看是否有对应结果