在实际的虚拟化环境使用过程中,由于一台物理机中开通多个虚拟机,如果不对虚拟机做限制,会造成虚拟机之间相互争抢物理机资源。

Linux中对资源控制这块已经做了一些工作,本文就是讲解Linux 对CPU资源的控制。

CPU调度策略

Linux中,每个进程能够占用CPU多久的时间,以及什么时候能够占用CPU是和系统的调度策略密切相关的。

Linux系统中有多种调度策略,各种调度策略有其适用的场景。

这里对调度策略不做过多说明,支持的调度策略如下:

/*

* Scheduling policies

*/

#define SCHED_NORMAL       0

#define SCHED_FIFO             1

#define SCHED_RR                2

#define SCHED_BATCH          3

/* SCHED_ISO: reserved but not implemented yet */

#define SCHED_IDLE               5

/* Can be ORed in to make sure the process is reverted back to SCHED_NORMAL on fork */

#define SCHED_RESET_ON_FORK     0x40000000

不过在查看Linux内核说明文档时,还有如下一句话:

"Any time not allocated to a realtime group will be used to run normal priority

tasks (SCHED_OTHER). Any allocated run time not used will also be picked up by

SCHED_OTHER"

大致意思是如果没有使用分配的时间,使用的调度策略就是SCHED_OTHER,也就是还有一种默认策略是SCHED_OTHER。

Linux 系统也提供了修改调度策略的命令和系统调用接口 -- 命令chrt。

查看一个虚拟机进程pid:

#ps axjf | grep 00dd

1   8647   8646   8646 ?            -1 Rl     107 6823:04 /usr/libexec/qemu-kvm -name instance-000000dd ... ...

通过chrt命令可以看到其使用的调度策略:

#chrt -p 8647

pid 8647's current scheduling policy: SCHED_OTHER

pid 8647's current scheduling priority: 0

可以将其修改成FIFO策略,优先级为10:

#chrt -p -f 10 8647

再次查看结果如下:

#chrt -p 8647

pid 8647's current scheduling policy: SCHED_FIFO

pid 8647's current scheduling priority: 10

说明:chrt的其他用法可以查看help。

进程的CPU资源控制

内核中提供全局资源控制,也提供有针对某个进程的局部资源控制方法cgroup。

全局资源控制

主要有两个参数决定:sched_rt_period_us 和 sched_rt_runtime_us。

通过sysctl接口可以查看:

#sysctl -n kernel.sched_rt_period_us         --> 进程调度的单位CPU时间 1s

1000000

#sysctl -n kernel.sched_rt_runtime_us       --> 进程在1s 内实际占用的cpu时间 0.95s

950000

默认设置说明进程在运行时并不是完全占用CPU的,每1秒中有0.05秒的时间可以给其它进程运行。

这样既不会对实时进程的响应时间造成太大的影响,也避免了实时进程卡住时导致整个系统无响应。

可以通过sysctl命令修改上述两个值,如:

#sysctl -w kernel.sched_rt_runtime_us=900000  设置为1s内进程实际占用的cpu时间为0.9s

局部资源控制

全局控制是针对所有进程的,局部控制是针对某个进程的,这里用到了linux的cgroup子系统。

如果想在 cgroup 中对 sched_rt_period_us 和 sched_rt_runtime_us 进行控制, 需要内核编译选项 CONFIG_RT_GROUP_SCHED=y

以centos6系统为例,如果安装了libcgroup安装包,那么系统中会有一个cgconfig服务,此服务启动后,会自动挂载cgroup各个组件。

内容如下:

cgroup /cgroup/cpuset cgroup rw,relatime,cpuset 0 0

cgroup /cgroup/cpu cgroup rw,relatime,cpu 0 0

cgroup /cgroup/cpuacct cgroup rw,relatime,cpuacct 0 0

cgroup /cgroup/memory cgroup rw,relatime,memory 0 0

cgroup /cgroup/devices cgroup rw,relatime,devices 0 0

cgroup /cgroup/freezer cgroup rw,relatime,freezer 0 0

cgroup /cgroup/net_cls cgroup rw,relatime,net_cls 0 0

cgroup /cgroup/blkio cgroup rw,relatime,blkio 0 0

这里只以/cgroup/cpu为例说明,此目录结构如下:

#/cgroup/cpu/

cgroup.event_control  cpu.cfs_period_us  cpu.rt_period_us   cpu.shares            release_agent

cgroup.procs          cpu.cfs_quota_us   cpu.rt_runtime_us  cpu.stat    notify_on_release  tasks

可以看到包含了cpu.rt_period_us和cpu.rt_runtime_us,其内容分别为:

#cat /cgroup/cpu/cpu.rt_period_us

1000000

#cat /cgroup/cpu/cpu.rt_runtime_us

950000

通过配置上述参数,就可以对/cgroup/cpu/tasks中记录的进程做限制,当然在该目录下还可以创建新的子目录结构,只限制某些进程。

cpu利用率控制

控制进程的资源使用率可以通过/cgroup/cpu/cpu.shares(默认值1024)来实现。

比如:

1. 有两个虚拟机instance-000000dd和instance-000000df,两个虚拟机cpu配置一样,内部跑stress(测试工具)将cpu跑到100%;

2. 在/cgroup/cpu/目录下创建目录instance-000000dd和instance-000000df,并将各自的进程号输入到/cgroup/cpu/instance-000000d*/tasks中;

3. 设置各自目录下的cpu.shares值;

3. 使用top命令查看两个虚拟机进程占用的物理机cpu百分比

当两个虚拟机的cpu.shares值均是默认值1024时,可以看到两个虚拟机占用的物理cpu百分比一样。

但是如果将instance-000000dd/cpu.shares设置为1024,instance-000000df/cpu.shares设置为512,可以看到instance-000000df占用的cpu为instance-000000dd的一半。

上述两个虚拟机,如果虚拟机instance-000000df不忙的时候,可以看到虚拟机instance-000000dd可以尽情的使用物理机的cpu资源。这种限制比较灵活,但是也有其缺点,因为还是会有竞争出现。

如果配合kernel scheduler里的cfs bandwidth control,可以做到对cpu资源的硬限制,即不管别的虚拟机是否繁忙,被限制的虚拟机消耗的cpu最多只能到达其被限制的水位。

有兴趣的可以看看cfs bandwidth control的用法。

cpu绑定

上面的例子中,虽然能够控制每个组的CPU的总体占用率,但是不能控制某个组的进程固定在某个物理CPU上运行。

要想将进程绑定到某个固定的CPU上, 需要使用cgroup的另一个组件 --  cpuset 子系统。

比如:

1. 在/cgroup/cpuset/下创建目录instance-000000dd,并将虚拟机instance-000000dd的进程号输入到instance-000000dd/tasks

2. 修改instance-000000dd/cpuset.cpus的值

#echo 0 > /cgroup/cpuset/instance-000000dd/cpuset.cpus     --> 将该虚拟机进程绑定到cpu0

#echo 0-7 > /cgroup/cpuset/instance-000000dd/cpuset.cpus  --> 将该虚拟机进程绑定到cpu0-7

3. 使用top命令查看虚拟机进程在物理机的哪个cpu运行,可以看到只会在绑定的cpu上调度。

Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐