Cgroups是什么
Cgroups全称control groups的简写,是Linux内核的一个功能,用来限制、控制与分离一个进程组的资源。
Cgroups 的工作目录为/sys/fs/cgroup,这个目录下包含了Cgroups所有的子系统的配置目录和控制文件,可以通过这些文件来控制Cgroups。
Cgroups的核心概念
1.任务(task)在cgroups中,任务就是系统的一个进程。
2.控制组(cgroup)一个cgroups包含一组进程,并可以在这个cgroups上增加子系统的各种参数配置,将一组进程和一组子系统关联起来。
3.子系统(subsystem)是一组资源控制模块,不同资源的具体管理工作由相应的子系统来实现。
4.层级树(hierarchy)主要功能是把cgroups串成一个树型结构,控制组被组织成了层级树的形式,每个控制组都可以包含其他的子控制组,可以做到继承,子控制组能使用的资源除了受本组配置的资源参数限制,还受到父级控制组设置的资源限制。
5.系统中的进程创建子进程时,该子进程自动成为其父进程所在控制组的成员,后续可以将该子系统移动到别的控制组中。
cpu子系统
cgroup有很多子系统,我们可以通过lssubsys -a命令查看当前内核支持哪些subsystem。
在这里主要介绍一下cpu子系统。
cpu子系统的工作目录是/sys/fs/cgroup/cpu,目录下包含了很多文件,可以通过这些控制文件实现对cpu资源的控制。
cpu.cfs_period_us:代表执行检测的周期,默认值是100000,单位是us。
cpu.cfs_quota_us:在一个检测周期内,容器能使用cpu的最大时间,默认是-1,也就是不做限制。设置成100000的话,就是1核。
cpu.shares:能获取CPU使用时间的相对值,相当于权重的概念,是软性控制。
cpu.stat:Cgroups 内的进程使用的 CPU 时间统计。
cpu.rt_period_us:执行检测的周期,默认是1s。
cpu.rt_runtime_us:在一个检测周期内,能使用的cpu最大时间,只作用于rt任务。
cpu子系统的使用案例
首先大家可以看到我的CPU是两个单核的CPU。
[root@localhost testgo] cat /proc/cpuinfo
processor : 0
.......
core id : 0
cpu cores : 1
......
power management:
processor : 1
......
core id : 0
cpu cores : 1
......
power management:
然后咱们运行一个炸弹程序,这个程序是由go编译成的,开启了3个Groutine的死循环,保证可以把我的CPU打满。
[root@localhost _data] cat main.go
package main
func main(){
go func() {
for {}
}()
go func() {
for {}
}()
go func() {
for {}
}()
select{}
}
[root@localhost _data] ./testgo
另外开启一个命令窗口,使用top查看下cpu使用情况,发现这个进程已经占用了200.0%的CPU,把cpu打满了。
[root@localhost testgo] top
top - 21:39:09 up 3:49, 2 users, load average: 0.97, 0.30, 0.14
Tasks: 171 total, 2 running, 169 sleeping, 0 stopped, 0 zombie
%Cpu(s): 96.9 us, 3.1 sy, 0.0 ni, 0.0 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
KiB Mem : 1863032 total, 146476 free, 873576 used, 842980 buff/cache
KiB Swap: 2098172 total, 2097148 free, 1024 used. 789564 avail Mem
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
8775 root 20 0 702352 724 388 R 200.0 0.0 0:43.28 testgo
8606 root 20 0 162100 2252 1520 R 6.7 0.1 0:00.01 top
我们在cpu子系统下创建一个Cgroups。可以看到我们在/sys/fs/cgroup/cpu/ 目录下创建文件夹后,系统自动在文件夹内创建了很多跟cpu子系统相关的文件。然后将我们的炸弹进程加入这个新创建的cpu子系统的Cgroups,并将cpu.cfs_quota_us改为100000。
[root@localhost testgo] cd /sys/fs/cgroup/cpu/
[root@localhost cpu] mkdir mytest
[root@localhost cpu] cd mytest/
[root@localhost mytest] ll
total 0
-rw-r--r--. 1 root root 0 Dec 9 21:41 cgroup.clone_children
--w--w--w-. 1 root root 0 Dec 9 21:41 cgroup.event_control
-rw-r--r--. 1 root root 0 Dec 9 21:41 cgroup.procs
-r--r--r--. 1 root root 0 Dec 9 21:41 cpuacct.stat
-rw-r--r--. 1 root root 0 Dec 9 21:41 cpuacct.usage
-r--r--r--. 1 root root 0 Dec 9 21:41 cpuacct.usage_percpu
-rw-r--r--. 1 root root 0 Dec 9 21:41 cpu.cfs_period_us
-rw-r--r--. 1 root root 0 Dec 9 21:41 cpu.cfs_quota_us
-rw-r--r--. 1 root root 0 Dec 9 21:41 cpu.rt_period_us
-rw-r--r--. 1 root root 0 Dec 9 21:41 cpu.rt_runtime_us
-rw-r--r--. 1 root root 0 Dec 9 21:41 cpu.shares
-r--r--r--. 1 root root 0 Dec 9 21:41 cpu.stat
-rw-r--r--. 1 root root 0 Dec 9 21:41 notify_on_release
-rw-r--r--. 1 root root 0 Dec 9 21:41 tasks
[root@localhost mytest] echo 8775 > cgroup.procs
[root@localhost mytest] echo 100000 > cpu.cfs_quota_us
再次查看top的显示情况,可以看到通过硬性限制这时cpu使用率已经降到了100%左右,这是因为cpu.cfs_quota_us设置的值等于cpu.cfs_period_us,也就刚好占用一个核的资源。
[root@localhost ~] top
top - 21:47:35 up 3:58, 3 users, load average: 0.94, 0.68, 0.37
Tasks: 173 total, 2 running, 171 sleeping, 0 stopped, 0 zombie
%Cpu(s): 48.8 us, 0.3 sy, 0.0 ni, 50.7 id, 0.0 wa, 0.0 hi, 0.2 si, 0.0 st
KiB Mem : 1863032 total, 137848 free, 877852 used, 847332 buff/cache
KiB Swap: 2098172 total, 2097148 free, 1024 used. 785256 avail Mem
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
8775 root 20 0 702352 480 268 R 99.7 0.0 1:32.05 testgo
8748 root 20 0 162100 2340 1572 R 0.3 0.1 0:00.83 top
下面咱们再开一个testgo的炸弹进程,并查看top,发现此时2个进程的cpu占有率几乎一样,分别占有一个核的资源。
top - 21:52:20 up 4:02, 4 users, load average: 2.56, 0.93, 0.50
Tasks: 176 total, 3 running, 173 sleeping, 0 stopped, 0 zombie
%Cpu(s): 99.3 us, 0.5 sy, 0.0 ni, 0.0 id, 0.0 wa, 0.0 hi, 0.2 si, 0.0 st
KiB Mem : 1863032 total, 133896 free, 881756 used, 847380 buff/cache
KiB Swap: 2098172 total, 2097148 free, 1024 used. 781320 avail Mem
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
8775 root 20 0 702352 480 268 R 100.0 0.0 6:16.38 testgo
8885 root 20 0 702352 480 268 R 99.0 0.0 0:18.61 testgo
1698 mysql 20 0 1121416 206400 1228 S 0.3 11.1 0:30.52 mysqld
2401 root 20 0 957552 34604 15568 S 0.3 1.9 0:34.30 containerd
把新开的炸弹进程加入到另外一个cgroup组里去。并修改它是cpu.shares为2048。再次查看top会发现8885这个进程的cpu占有率约等于8775这个进程的2倍。这是因为8885进程所在Cgroups的cpu.shares是另外一个进程所在Cgroups的2倍。
[root@localhost mytest2] echo 8885 > cgroup.procs
[root@localhost mytest2] echo 2048 > cpu.shares
[root@localhost ~] top
top - 21:54:24 up 4:04, 4 users, load average: 4.62, 2.32, 1.07
Tasks: 176 total, 3 running, 173 sleeping, 0 stopped, 0 zombie
%Cpu(s): 99.5 us, 0.3 sy, 0.0 ni, 0.0 id, 0.0 wa, 0.0 hi, 0.2 si, 0.0 st
KiB Mem : 1863032 total, 133588 free, 882060 used, 847384 buff/cache
KiB Swap: 2098172 total, 2097148 free, 1024 used. 781016 avail Mem
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
8885 root 20 0 702352 480 268 R 133.6 0.0 2:29.48 testgo
8775 root 20 0 702352 480 268 R 66.8 0.0 8:11.56 testgo
8906 root 20 0 162100 2344 1572 R 0.7 0.1 0:00.18 top
通过案例发现cpu.shares是个软性的控制,在没有其他进程竞争资源的情况下,单独使用cpu.shares是不能使cpu负载降低。
而cpu.cfs_quota_us是硬性的指定进程能在一个检测周期内获得的cpu使用时间