KVM虚拟机cpu资源限制和vcpu亲缘性绑定
前言
KVM中添加的实例存在资源分布不均的情况,这样如果有消耗资源的实例会影响到其他实例的服务正常运行,所以给kvm做资源限制是很有必要的,下面记录一下在centos7中KVM环境下使用cgroup限制vm实例资源的过程。
安装cgroup
[root@yufu ~]# yum install libcgroup libcgroup-devel libcgroup-tools-y
启动cgroup服务
[root@yufu ~]# systemctl start cgconfig
[root@yufu ~]# systemctl enable cgconfig
默认安装后目录文件并没有在/cgroup 目录下,而是在/sys/fs/cgoup 目录下。可以说使用
find / -type d -name cgroup
查找目录。
限制cpu资源
查看当前宿主机上有哪些实例并查看实例的进行号。
使用ps -ef
指令可以看到每个vm实例的进程号,一个示列在宿主机中就是一个进程。【通过进程名称查看进程号:pidof qemu-kvm
】
下面使用进程为 2106 的这个vm实例进测试:
进程号 2106 对应的实例是vm5,内存4G,cpu为2核心
在实例vm4中写一个消耗cpu的脚本测试,在宿主机中查看该进程消耗的cpu资源
#! /bin/bash
x=0
while [ True ];do
x=$x+1
done;
宿主机执行 top -p 2106
查看进程状态
Tasks: 1 total, 0 running, 1 sleeping, 0 stopped, 0 zombie
%Cpu(s): 4.2 us, 0.0 sy, 0.0 ni, 95.8 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
KiB Mem : 98821584 total, 95922736 free, 2029444 used, 869412 buff/cache
KiB Swap: 8388604 total, 8388604 free, 0 used. 96262080 avail Mem
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
2106 qemu 20 0 4549900 566812 9336 S 100.0 0.6 11:47.26 qemu-kvm
可以看到cpu已经使用了100%
下面用cgroup控制这个进程的cpu资源
要对vm实例做资源限制,在cgroup目录下创建一个资源组vm5,然后在这个资源组中定义资源分配(可以一个vm定义一个资源组,容易管理,也可以给所有vm定义一个资源组)
- 创建资源组
[root@yufu ~]# mkdir /sys/fs/cgroup/cpu/vm5
#资源组创建以后会有很多控制文件
[root@yufu ~]# ls /sys/fs/cgroup/cpu/vm5
cgroup.clone_children cpuacct.stat cpu.cfs_period_us cpu.rt_runtime_us notify_on_release
cgroup.event_control cpuacct.usage cpu.cfs_quota_us cpu.shares tasks
cgroup.procs cpuacct.usage_percpu cpu.rt_period_us cpu.stat
查看当前进程
[root@yufu ~]# pidof qemu-kvm
2106 1642
- 添加控制进程
将要限制的进程号加入到/sys/fs/cgroup/cpu/vm5/cgroup.procs
[root@yufu ~]# echo 2106 > /sys/fs/cgroup/cpu/vm5/cgroup.procs
- 限制cpu资源使用
cpu.cfs_period_us和cpu.cfs_quota_us来限制该组中的所有进程在单位时间里可以使用的cpu时间。这里的cfs是完全公平调度器的缩写。cpu.cfs_period_us就是时间周期(微秒),默认为100000,即百毫秒。cpu.cfs_quota_us就是在这期间内可使用的cpu时间(微秒),默认-1,即无限制。
- 查看默认值
[root@yufu ~]# cat /sys/fs/cgroup/cpu/vm5/cpu.cfs_period_us
100000
[root@yufu ~]# cat /sys/fs/cgroup/cpu/vm5/cpu.cfs_quota_us
-1
- 对上面的两个值做调整
[root@yufu ~]# echo 80000 > /sys/fs/cgroup/cpu/vm5/cpu.cfs_period_us
[root@yufu ~]# echo 40000 > /sys/fs/cgroup/cpu/vm5/cpu.cfs_quota_us
- 再执行脚本测试
在vm5上执行测试脚本,宿主机查看top
Tasks: 1 total, 0 running, 1 sleeping, 0 stopped, 0 zombie
%Cpu(s): 2.1 us, 0.0 sy, 0.0 ni, 97.9 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
KiB Mem : 98821584 total, 95904496 free, 2047560 used, 869528 buff/cache
KiB Swap: 8388604 total, 8388604 free, 0 used. 96243984 avail Mem
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
2106 qemu 20 0 4549900 567324 9336 S 50.0 0.6 12:02.15 qemu-kvm
对比发现:长时间高负载下,限制了cpu资源的vm实例负载比没有做限制的实例负载要小。
同样,其他虚拟机实例按照上面同样的方式也可以对cpu资源进行限制
撤销资源限制
要撤销某个资源的限制,将该资源组中的tasks中的pid写到根 cgroup 的 tasks 文件即可,因为每个进程都属于且只属于一个 cgroup,加入到新的 cgroup 后,原有关系也就解除了。要删除一个 cgroup,可以用 rmdir 删除相应目录。不过在删除前,必须先让其中的进程全部退出,对应子系统的资源都已经释放,否则是无法删除的。
- 撤销资源
[root@yufu vm5]# echo 2106 > /sys/fs/cgroup/cpu/tasks
[root@yufu vm5]# echo 2111 > /sys/fs/cgroup/cpu/tasks
[root@yufu vm5]# echo 2112 > /sys/fs/cgroup/cpu/tasks
- 查看原来vm5实例中的pid已经被清空了
[root@yufu vm5]# cat tasks
再执行脚本测试,cpu又是100%
Tasks: 1 total, 0 running, 1 sleeping, 0 stopped, 0 zombie
%Cpu(s): 4.1 us, 0.0 sy, 0.0 ni, 95.9 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
KiB Mem : 98821584 total, 95905520 free, 2046364 used, 869704 buff/cache
KiB Swap: 8388604 total, 8388604 free, 0 used. 96245000 avail Mem
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
2106 qemu 20 0 4549900 567324 9336 S 100.0 0.6 14:29.49 qemu-kvm
KVM中虚拟机的cpu亲缘性绑定
默认情况下,kvm虚拟机实例并没有对vcpu做任何限制,当一个实例负载过高时,vcpu会在宿主机的cpu上来回切换,频繁的切换容易造成资源浪费,将vcpu与宿主机cpu对应绑定,能够有效提升cpu工作效率。
也可以将一个进程绑定在一个cpu上,使用taskset指令
cpu绑定方式
上面提到过,一个vm实例在宿主机中其实就是一个进程,绑定方式有两种:
taskset指令绑定进程cpu
使用taskset绑定是以vm实例上的所有vcpu为单位,与宿主机上的cpu进行绑定。比如:将vm4实例绑定在第4号cpu上,那么vm4实例中有4个vcpu,这4个vcpu都工作在了宿主机的第4号cpu上了。这种绑定方式粒度比较大
vcpupin子命令绑定
virsh vcpupin 子命令是KVM自带的指令工具,它可以把vm实例的每个vcpu与宿主机的cpu对应绑定,这种绑定方式粒度更小。
下面以vm4实例为例,查看其cpu运行情况和对其进程绑定
- 查看vm4当前cpu绑定情况:
[root@yufu ~]# virsh vcpupin vm4
VCPU: CPU Affinity
----------------------------------
0: 0-23
1: 0-23
#默认2个vcpu没有进行绑定,可以在0-24号cpu上切换
- 查看vcpu使用的时间
[root@yufu ~]# virsh vcpuinfo vm4
VCPU: 0
CPU: 10 #运行在10号cpu上
State: running
CPU time: 14.2s
CPU Affinity: yyyyyyyyyyyyyyyyyyyyyyyy
VCPU: 1
CPU: 8 #运行在8号cpu上
State: running
CPU time: 6.8s
CPU Affinity: yyyyyyyyyyyyyyyyyyyyyyyy
- 将vm4的两个vcpu绑定在宿主机的第4号和第6号cpu上
cpu编号从0开始计数
[root@yufu ~]# virsh vcpupin vm4 0 3
[root@yufu ~]# virsh vcpupin vm4 1 5
- 再看vcpu状态
[root@yufu ~]# virsh vcpuinfo vm4
VCPU: 0
CPU: 3
State: running
CPU time: 14.5s
CPU Affinity: ---y--------------------
VCPU: 1
CPU: 5
State: running
CPU time: 7.3s
CPU Affinity: -----y------------------
[root@yufu ~]# virsh vcpupin vm4
VCPU: CPU Affinity
----------------------------------
0: 3
1: 5
可以看到cpu已经绑定了,此时在vm4上做压力测试并在宿主机上看看cpu运行情况
上面使用指令绑定的方式只在当前系统环境有效,实例重启后就会失效,要永久生效需要在xml配置文件中定义
接着再把vm4的cpu使用资源做cgroup限制就就可以了:
-
执行
ps -ef
获得vm4的pid为1636 -
创建cgroup资源组vm4
[root@yufu ~]# mkdir /sys/fs/cgroup/cpu/vm4
- 将vm4的pid写进cgroup.procs文件
[root@yufu ~]# cd /sys/fs/cgroup/cpu/vm4/
[root@yufu vm4]# echo 1636 > cgroup.procs
#当把进程pid加到 cgroup.procs后,系统会自动将该进程和进程下的线程加入到tasks文件中
[root@yufu vm4]# echo 80000 > cpu.cfs_period_us
[root@yufu vm4]# echo 40000 > cpu.cfs_quota_us
- 运行vm4消耗cpu脚本,查看宿主机进程状态和cpu
可以看到htop中,两个线程的cpu使用率一直在50%左右,且负载一直在第4个第6号cpu运行(这里就不上图了)
将cpu绑定信息写到xml配置文件
上面提到过,在命令行做的设置后,vm实例重启后,绑定信息就会失效,要想永久生效,需要将cpu的绑定信息写到该实例的xml配置文件中。
- 在配置xml配置文件中添加绑定信息
停止vm4实例,编辑其xml文件
<domain type='kvm'>
<name>vm4</name>
<uuid>a140824a-800b-42bf-ae26-60e9ec6aa50f</uuid>
<memory unit='KiB'>4097152</memory>
<currentMemory unit='KiB'>4097152</currentMemory>
<vcpu placement='static'>2</vcpu>
#以下为添加内容
<cputune>
<vcpupin vcpu='0' cpuset='3'/>
<vcpupin vcpu='1' cpuset='5'/>
</cputune>
- 修改配置文件后要重载xml文件
[root@yufu qemu]# virsh define /etc/libvirt/qemu/vm4.xml
再启动实例查看vcpu绑定信息
[root@yufu qemu]# virsh vcpuinfo vm4
VCPU: 0
CPU: 3
State: running
CPU time: 14.2s
CPU Affinity: ---y--------------------
VCPU: 1
CPU: 5
State: running
CPU time: 4.3s
CPU Affinity: -----y------------------
[root@yufu qemu]# virsh vcpupin vm4
VCPU: CPU Affinity
----------------------------------
0: 3
1: 5
关于kvm虚拟机的cpu优化和资源限制暂时记录到这里,后面有时间再对内存和io进行总结