虚拟机资源Qos分析
条评论一.虚拟机资源Qos
虚拟化资源Qos在云计算场景中有着很重要的作用,可以支持虚拟机的弹性负载,提高硬件复用率,减少资源浪费, 降低企业成本等。虚拟机的资源Qos包括CPU,memory,IO,网络几个方面
二.CPU Qos
CPU Qos控制包括CPU 热插拔、CPU 份额、CPU 配额。
1.CPU 热插拔
cpu热插拔可以帮助虚拟机在高负载的情况下,不用停机直接通过热插拔cpu的方式为虚拟机进行弹性扩展,保证虚拟机里的业务稳定,虚拟化场景中配置cpu支持热插拔的xml格式如下:
1 | <vcpu placement='static' current='3'>6</vcpu> |
vcpu元素中的current属性表示当前可以使用cpu的数量,6则表示支持的最大的cpu数量;
vcpus元素中则是详细描述了每个cpu的控制状态:id值代表每个vcpu的id,这个值会在libvirt中被用作vcpu pining、调度信息以及numa分配,在某些情况下这个值可能和虚拟机看到的id不同,默认vcpu id从0开始;enabled表示在虚拟机启动的时候哪些cpu为随机启动,vcpu 0默认enabled=’yes’(虚拟机启动至少要有一个vcpu);hotpluggable表示当前vcpu是否允许热插拔,vcpu 0默认不支持热插拔; order代表vcpu在虚拟机中online的顺序(hypervisor可能会在某些操作中为了确保有效的配置而会清楚或更新order),其中vcpu的启动必须在vcpu0之后。
另外不是所有的hypervisor都支持cpu热插拔,还有的像PPC64这种平台的cpu热插,如果vcpu都在一个core上,则必须都需要enabled
2.CPU份额
CPU份额表示进程在调度器中所占的权重,在虚拟化场景中,当CPU资源紧张时,可以为不同类型的虚拟机配置不同的CPU份额,例如,为一些承载关键业务的虚拟机配置高份额,保证其CPU资源的稳定。CPU配额libvirt中配置如下:
1 | <cputune> |
在linux内核中,默认所使用的进程调度器为cfs,cfs调度器会根据cgroup的cpu子系统下的每个cgroup子组的cpu.shares计算进程的weight值,cpu.shares的值是一个相对值,cfs是根据比例计算,默认所有进程的权重值是一样的(默认值1024),即所有进程的权重比例为1:1:1…,kvm中,libvirtd进程启动后会在cpu子系统中建立一个名为machine.slice的文件夹(即代表一个子组),之后在创建虚拟机的时候会在machine.slice下为虚拟机创建一个machine-qemu开头的文件夹,然后在这个文件夹下会为每个vcpu创建一个文件夹(会将每个vcpu线程加入对应的文件夹下的task),同时还会创建一个emulator文件夹(将qemu中除了vcpu线程的其他线程加入到这个文件夹下的task中),另外libvirt在创建虚拟机的时候支持为不同的虚拟机配置不同的cpu share值,这就决定了cfs在调度的时候通过获取每个虚拟机子组中cpu.shares值计算虚拟机的调度优先级,上面xml中的shares值会写进为虚拟机创建machine-qemu开头文件夹下的cpu.shares里,vcpu与emulator的cpu.shares都是默认值1024,即qemu中所有线程的调度权重相等,但不同的qemu进程会由于shares值不同,导致在调度器的权重不同。
3.CPU配额
CPU配额表示限制cpu使用率,通过为不同的虚拟机配置不同的配额,可以防止虚拟机资源消耗过多,同时也可以间接保证一些关键虚拟机的CPU资源。在libvirt中支持三中配置: vcpu配置配额,为整个虚拟机配置配额(即为整个qemu进程配置配额),为io线程配置配额,CPU配额在libvirt中配置如下:
1 | <cputune> |
在cgroup的cpu子系统下面有cpu.cfs_period_us和cpu.cfs_quota_us两个文件两个文件,cpu.cfs_period_us代表cpu分配的周期(微秒),默认为100000。cpu.cfs_quota_us表示该control group限制占用的时间(微秒),默认为-1,表示不限制。如果设为50000,表示占用50000/10000=50%的CPU。上述配置中的period/quota代表的是配置vcpu的配额,global_period/global_quota代表的是配置qemu整个进程(包括所有子线程)的配额,iothread_period/iothread_quota代表的是配置io线程的配额,libvirt支持配置iothread,iothread的作用是增加qemu中设备io的处理能力,emulator_period/emulator_quota代表的是qemu线程中除了vcpu线程外的其他线程的配额
三.内存Qos
内存Qos包括内存热插拔、内存balloon、内存控制
1.内存热插拔
内存热插拔和CPU热插拔类似,都是在虚拟机处于高内存负载的时候,通过热插拔内存,为虚拟机提供动态扩展,保证虚拟机的高可用。libvirt中内存热插拔的配置如下:
1 | <maxMemory slots='16' unit='KiB'>16777216表示支持的最大内存,memory表示当前可用内存,热插内存的时候需要主要slots</maxMemory> |
maxMemory中的slots表示有16个内存插槽,16777216表示支持的最大内存,memory表示当前可用内存,热插内存的时候需要主要slots与最大内存两个条件都必须满足才能进行热插,如果热插了15根512M的内存,再热插一个1G的内存,虽然最大内存的上限仍未达到,但是插槽已经满了,仍然不能热插内存了
2.内存balloon
内存balloon是通过给虚拟机增加一个virtio-balloon的设备,同时在虚拟机内安装virtio-balloon驱动,使用可以根据虚拟机配置动态的调账虚拟机可用内存,内存balloon在libvirt配置如下:
1 | <memory unit='KiB'>4194304</memory> |
当currentMemory小于memory时,qemut通过virtio-balloon设备将memory-currentMemory的差值发送给虚拟机中virtio-balloon驱动,virtio-balloon会根据差值做出相应的inflate或deflate操作(即释放或申请内存)
3.内存控制
内存控制是利用cgroup的memory子系统的能力达到限制虚拟机的内存使用,memory子系统下同样也是针对每个虚拟机有一个相应的machine-qemu开头的子组,通过更改虚拟机对应子组下面的soft_limit_in_bytes、limit_in_bytes、memsw.limit_in_bytes等参数,可以控制虚拟机的内存使用限制,libvirt中内存控制的配置如下:
1 | <memtune> |
hard_limit表示虚拟机可以使用的物理内存的上限,因此hard_limit的值会写入到memory子系统的limit_in_bytes文件;
soft_limit表示当系统内存不足时,通过判断虚拟机的内存是否超过soft_limit确定是否需要回收虚拟机的内存,soft_limit的值会写入到soft_limit_in_bytes文件;
swap_hard_limit表示虚拟机可以使用包括物理内存和交换内存的总和的大小,swap_hard_limit的值会写入到memsw.limit_in_bytes文件,另外需要注意的是hard_limit必须小于等于swap_hard_limit,否则swap_hard_limit无法写入memsw.limit_in_bytes
四.磁盘IO Qos
磁盘IO是通过Cgroup实现控制虚拟机的IO读写,对磁盘IO的控制可以帮忙降低虚拟机并发启动时的IO风暴以及定位一些异常高IO的虚拟机。磁盘IO在libvirt中的配置有两种:
第一种是blkiotune的配置,如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15<blkiotune>
<weight>800</weight>
<device>
<path>/dev/sda</path>
<weight>1000</weight>
</device>
<device>
<path>/dev/sdb</path>
<weight>500</weight>
<read_bytes_sec>10000</read_bytes_sec>
<write_bytes_sec>10000</write_bytes_sec>
<read_iops_sec>20000</read_iops_sec>
<write_iops_sec>20000</write_iops_sec>
</device>
</blkiotune>第二种是iotune的配置,如下:
1
2
3
4
5
6
7
8
9
10
11
12<disk type='file' snapshot='external'>
<driver name="tap" type="aio" cache="default"/>
<source file='/var/lib/xen/images/fv0' startupPolicy='optional'>
<seclabel relabel='no'/>
</source>
<target dev='hda' bus='ide'/>
<iotune>
<total_bytes_sec>10000000</total_bytes_sec>
<read_iops_sec>400000</read_iops_sec>
<write_iops_sec>100000</write_iops_sec>
</iotune>
</disk>
iotune是针对每个虚拟机的磁盘块设备限制io读写,iotune是基于qemu中块设备的io流控实现的,libvirt通过调用block_set_io_throttle命令通知qemu需要设置Qos的设备以及参数。上述配置中的total_bytes_sec表示每秒允许的最大字节数;read_iops_sec表示每秒允许的读iops量;write_iops_sec表示每秒允许的写iops量