0%

linux资源管理器--cgroups理解

cgroups是control groups的缩写,即控制组,是Linux内核提供的一种可以限制,记录,隔离进程组所使用的物理资源的机制.它是实现Linux容器如lxc,docker等的基础之一

简而言之,它负责控制进程使用的系统资源=_=.官方文档:https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/Documentation/cgroup-v1/cgroups.txt?h=v4.18-rc1

原理

cgroups的实现本质上是给系统进程挂上钩子(hooks),当task运行的过程中涉及到某个资源时就会触发钩子上所附带的subsystem进行检测,最终根据资源类别的不同使用对应的技术进行资源限制和优先级分配

cgroups的目的是将任意进程进行分组化管理.

cgroups本身提供将进程进行分组化管理的功能,而IO或内存的分配等具体的资源管理功能则是通过subsystem来实现的.可以通过/proc/cgroup查看可以使用的subsystem

cgroups提供了一个名为cgroup的虚拟文件系统,作为进行分组管理和各子系统设置的用户接口.要使用cgroups,必须挂载cgroup文件系统,此时可以通过挂载参数指定使用的subsystem

在linux中,cgroups默认挂载在/sys/fs/cgroup目录,其中包含了所有的子系统以及每个子系统的层级

cgroups相关概念

cgroups主要由task,cgroup,subsystem以及hierarchy组成

  • task(任务): 在cgroups中,任务就是系统的一个进程
  • cgroup(控制族群): 控制族群是一组按照某种标准划分的进程.cgroups中的资源控制都是以控制族群为单位实现的.一个进程可以加入某个控制族群,也可以迁移至另一个控制族群
  • hierarchy(层级): 控制族群可以组织成层级的形式,即一颗控制族群树,其上的子节点继承父节点的特定属性(我觉得层级这个名称不好,直接讲cgroup树得了)
  • subsystem(子系统): 通常是一个资源控制器.例如CPU子系统可以控制CPU时间分配.一个子系统必须附加到控制族群树上才能起作用,该树上的所有控制族群都受到该子系统的控制

子系统简介

subsystem实际上就是cgroups的资源控制系统,每种subsystem独立地控制一种资源

  • blkio: 这个subsystem可以为块设备设定输入/输出限制,比如物理驱动设备(包括磁盘,固态硬盘,USB等)
  • cpu: 这个subsystem使用调度程序控制task对CPU的使用
  • cpuacct: 这个subsystem自动生成cgroup中task对CPU资源使用情况的报告
  • cpuset: 这个subsystem可以为cgroup中的task分配独立的CPU(此处针对多处理器系统)和内存
  • devices: 这个subsystem可以开启或关闭cgroup中task对设备的访问
  • freezer: 这个subsystem可以挂起或恢复cgroup中的task
  • memory: 这个subsystem可以设定cgroup中task对内存使用量的限定,并且自动生成这些task对内存资源使用情况的报告
  • perfevent: 这个subsystem使用后使得cgroup中的task可以进行统一的性能测试
  • *net_cls: 这个subsystem Docker没有直接使用,它通过使用等级识别符(classid)标记网络数据包,从而允许Linux流量控制程序(TC:Traffic Controller)识别从具体cgroup中生成的数据包

cgroups规则

在任务,控制族群,层级,子系统间有着一些规则:

  1. 同一个hierarchy能够附加一个或多个subsystem
  2. 一个subsystem只能附加到一个hierarchy上
  3. 每次在系统中创建新层级时,该系统中的所有任务都是那个层级的默认cgroup(我们称之为root cgroup,此cgroup在创建层级时自动创建,后面在该层级中创建的cgroup都是此cgroup的后代)的初始成员
  4. 一个任务可以是多个cgroup的成员,但是这些cgroup必须在不同的层级
  5. 进程创建子进程时,该子进程自动成为其父进程所在的cgroup的成员.可根据需要将其移至其它cgroup中

验证:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
]# ls /sys/fs/cgroup
drwxr-xr-x. 2 root root 0 Mar 7 21:12 blkio
lrwxrwxrwx. 1 root root 11 Mar 7 21:12 cpu -> cpu,cpuacct
lrwxrwxrwx. 1 root root 11 Mar 7 21:12 cpuacct -> cpu,cpuacct
drwxr-xr-x. 3 root root 0 Mar 7 21:12 cpu,cpuacct
drwxr-xr-x. 3 root root 0 Mar 7 21:12 cpuset
drwxr-xr-x. 4 root root 0 Mar 7 21:12 devices
drwxr-xr-x. 2 root root 0 Mar 7 21:12 freezer
drwxr-xr-x. 2 root root 0 Mar 7 21:12 hugetlb
drwxr-xr-x. 2 root root 0 Mar 7 21:12 memory
lrwxrwxrwx. 1 root root 16 Mar 7 21:12 net_cls -> net_cls,net_prio
drwxr-xr-x. 2 root root 0 Mar 7 21:12 net_cls,net_prio
lrwxrwxrwx. 1 root root 16 Mar 7 21:12 net_prio -> net_cls,net_prio
drwxr-xr-x. 2 root root 0 Mar 7 21:12 perf_event
drwxr-xr-x. 2 root root 0 Mar 7 21:12 pids
drwxr-xr-x. 4 root root 0 Mar 7 21:12 systemd

可以看到,每个目录都是一个层级,一个子系统只能在一个层级,而其中的cpu,cpuacct层级有着cpucpuacct子系统,net_cls,net_prio层级有着net_clsnet_prio子系统

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
]# ls -l /sys/fs/cgroup/cpuset
-rw-r--r--. 1 root root 0 Mar 7 21:12 cgroup.clone_children
--w--w--w-. 1 root root 0 Mar 7 21:12 cgroup.event_control
-rw-r--r--. 1 root root 0 Mar 7 21:12 cgroup.procs
-r--r--r--. 1 root root 0 Mar 7 21:12 cgroup.sane_behavior
-rw-r--r--. 1 root root 0 Mar 7 21:12 cpuset.cpu_exclusive
-rw-r--r--. 1 root root 0 Mar 7 21:12 cpuset.cpus
-r--r--r--. 1 root root 0 Mar 7 21:12 cpuset.effective_cpus
-r--r--r--. 1 root root 0 Mar 7 21:12 cpuset.effective_mems
-rw-r--r--. 1 root root 0 Mar 7 21:12 cpuset.mem_exclusive
-rw-r--r--. 1 root root 0 Mar 7 21:12 cpuset.mem_hardwall
-rw-r--r--. 1 root root 0 Mar 7 21:12 cpuset.memory_migrate
-r--r--r--. 1 root root 0 Mar 7 21:12 cpuset.memory_pressure
-rw-r--r--. 1 root root 0 Mar 7 21:12 cpuset.memory_pressure_enabled
-rw-r--r--. 1 root root 0 Mar 7 21:12 cpuset.memory_spread_page
-rw-r--r--. 1 root root 0 Mar 7 21:12 cpuset.memory_spread_slab
-rw-r--r--. 1 root root 0 Mar 7 21:12 cpuset.mems
-rw-r--r--. 1 root root 0 Mar 7 21:12 cpuset.sched_load_balance
-rw-r--r--. 1 root root 0 Mar 7 21:12 cpuset.sched_relax_domain_level
-rw-r--r--. 1 root root 0 Mar 7 21:12 notify_on_release
-rw-r--r--. 1 root root 0 Mar 7 21:12 release_agent
-rw-r--r--. 1 root root 0 Mar 7 21:12 tasks

该目录是cpuset层级(也是cpuset子系统)的默认cgroup,也就是根cgroup,该cgroup的tasks文件包含系统的所有进程

1
2
[root@staight cpuset]# mkdir test&& cd test
[root@staight test]# echo 1000 >> tasks

创建一个子cgroup,在默认为空的tasks中添加1000进程,此时去查看父cgroup的tasks,原来的1000进程会消失.因此在一个层级中,一个进程只能存在于唯一的cgroup

常用命令

查看系统所用到的子系统:

1
2
3
4
5
6
7
8
9
10
11
[root@staight test]# lssubsys 
cpuset
cpu,cpuacct
memory
devices
freezer
net_cls,net_prio
blkio
perf_event
hugetlb
pids

查看当前所有的cgroup:

1
2
3
4
5
6
7
8
9
10
11
12
13
[root@staight test]# lscgroup 
cpu,cpuacct:/
cpu,cpuacct:/test
net_cls,net_prio:/
hugetlb:/
devices:/
memory:/
pids:/
blkio:/
perf_event:/
freezer:/
cpuset:/
cpuset:/test

在指定cgroup中启动指定进程:

1
[root@staight shell]# cgexec -g cpu,cpuacct:/test ./cpu_max.sh

将进程添加至指定cgroup:

1
[root@staight shell]# cgclassify -g cpuset:/test 1000

设置指定cgroup的参数:

1
[root@staight shell]# cgset -r cpuset.cpus=0-1 cpuset:/

参考文档

CGroup 介绍、应用实例及原理描述

Docker 背后的内核知识——cgroups 资源限制