Linux Cgroups技术介绍与实践
什么是Cgroups
Linux Cgroups (Control Groups )提供了对 组进程及将来子进程的资源限制、控制和统
计的能力,这些资源包括 CPU、内存、存储、网络等通过Cgroups,可以方便地限制某个进
程的资源占用,并且可以实时地监控进程的监控和统计信息。
Cgroups中的3个组件
-
cgroup是对进程分组管理的一种机制,cgroup包含一组进程,并可以在这个cgroup上增加Linux subsystem的各种参数配置,将一组进程和subsystem的系统参数关联起来。 -
subsystem是一组资源控制的模块,每个subsystem会关联到定义了相应限制的cgroup上,并对这个cgroup中的进程做相应的限制和控制,如限制这个cgroup中的进程的内存数,cpu核心数等 -
hierarchy的功能是把cgroup串成一个树状的结构,一个这样的树便是hierarchy,通过这种树状结构,Cgroups可以做到继承。比如,系统对一组定时的任务进程通过cgroup限制了CPU的使用率,然后其中有一个定时dump日志的进程还需要限制磁盘IO,为了避免限制了磁盘IO之后影响到其他进程,就可以创建cgroup2,使其继承于cgroup并限制磁盘的IO,这样cgroup2便继承了cgroup1中对CPU使用率的限制,并且增加了磁盘IO的限制而不影响到cgroup1中的其他进程。
三个组件的关系
- 系统在创建了新的
hierarchy之后,系统中所有的进程都会加入这个hierarchy cgroup根节点,这个cgroup根节点是hierarchy默认创建的, - 一个
subsystem只能附加到一个hierarchy上面 - 一个
hierarchy可以附加多个subsystem - 一个进程可以作为多个
cgroup的成员,但是这些cgroup必须在不同的hierarchy - 一个进程
fork出子进程时,子进程是和父进程在同一个cgroup中的,也可以根据需要将其移动到其他cgroup
操作Cgroups
1.创建并挂在一个hierarchy(cgroup树)
mkdir cgroupTest #创建一个hierarchy挂载点
sudo mount -t cgroup -o none,name=cgroupTest cgroupTest ./cgroupTest #挂载一个hierarchy
ls cgroupTest #挂载后我们就可以看到系统在这个目录下生成了一些默认文件
cgroup.clone_children cgroup.procs cgroup.sane_behavior
notify_on_release release_agent tasks
这些文件就是这个hierarchy cgroup根节点的配置项,上面这些文件的含义分别如下。
-
cgroup.clone_children:cpuset的subsystem会读取这个配置文件,如果这个值是1(默认是0),子cgroup才会继承父cgroup的cpuset配置 -
cgroup.procs:是树中当前节点cgroup中的进程组ID,现在的位置是在根节点,这个文件中会有现在系统中所有进程组的ID -
notify_on _release和release agent会一起使用。notify on release标识当这个cgroup最后一个进程退出的时候是否执行了release_agent;release_ agent则是一个路径,通常用作进程退出之后自动清理掉不再使用的cgroup -
tasks标识cgroup下面的进程ID,如果把一个进程ID写到tasks文件中,便会将相应的进程加入到这个cgroup
2.创建hierarchy cgroup根节点中扩展出的两个子cgroup
sudo mkdir cgroup-1 #创建子cgroup cgroup-1
sudo mkdir cgroup-2 #创建子cgroup cgroup-2
tree
.
├── cgroup-1
│ ├── cgroup.clone_children
│ ├── cgroup.procs
│ ├── notify_on_release
│ └── tasks
├── cgroup-2
│ ├── cgroup.clone_children
│ ├── cgroup.procs
│ ├── notify_on_release
│ └── tasks
├── cgroup.clone_children
├── cgroup.procs
├── cgroup.sane_behavior
├── notify_on_release
├── release_agent
└── tasks
可以看到,在cgroup的目录下创建文件夹时,Kernel会把文件夹标记为这个cgroup的子cgroup,它们会继承父cgroup的属性。
3.cgroup中添加和移动进程
一个进程在Cgroups hierarchy中,只能在一个cgroup节点上存在,系统的所有进程都会默认在根节点上存在,将进程移动到其他cgroup节点,只需要将进程ID到移动到的cgroup节点的tasks文件中即可。
cd cgroup-1
echo $$ #当前终端的进程id
27461
sudo sh -c "echo $$ >> tasks" # 将我所在的终端进程移动到cgroup-1
cat /proc/27461/cgroup
15:name=cgroupTest:/cgroup-1
14:name=systemd:/
13:rdma:/
12:pids:/
11:hugetlb:/
10:net_prio:/
9:perf_event:/
8:net_cls:/
7:freezer:/
6:devices:/
5:memory:/
4:blkio:/
3:cpuacct:/
2:cpu:/
1:cpuset:/
0::/
可以看到, 前的27461进程己经被加到cgroup-test:/cgroup-1中了。
4.通过subsystem限制cgroup中进程的资源
在上面创建hierarchy的时候,这个hierarchy并没有关联到任何的subsystem,所以没办法通过那个hierarchy中的cgroup节点限制进程的资源占用,其实系统默认已经为每个subsystem创建了一个默认的hierarchy,比如memory hierarchyo
mount | grep memory #
cgroup on /sys/fs/cgroup/memory type cgroup (rw,nosuid,nodev,noexec,relatime,memory)
可以看到,/sys/fs/cgrou/memory目录便是挂在了memory subsystem hierarchy 上。下面,就通过在这个 hierarchy中创建cgroup,限制如下进程占用的内存。
cd /sys/fs/cgroup/memory
# 首先,在不做限制的情况下,启动一个占用200MB内存的stress进程
stress --vm-bytes 200m --vm-keep -m 1
#这时打开另一个终端输入top命令
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
31132 root 20 0 208664 204952 272 R 100.0 2.5 0:12.49 stress
#可以看到%MEM占用为2.5%,因为我linux系统内存为8GB
#接下来切换终端回来
#创建一个cgroup
sudo mkdir test-limit-memory && cd test-limit-memory
#设置该cgroup的最大内存占用为1OOMB
sudo sh -c "echo "lOOm" > memory.limit_in_bytes"
#将当前进程移动到这个 cgroup
sudo sh -c "echo $$ > tasks"
#再次运行占用内存 200MB stress 进程
stress --vm-bytes 200m --vm-keep -m 1
#查看刚刚那个运行了top的终端
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
31132 root 20 0 208664 10164 272 R 100.0 1.3 0:12.49 stress
#可以看到内存占用变为1.3%,缩小为一半










