- cgroup概述
- cgroups 功能及核心概念
- Linux内核代码中Cgroups的实现
- cgroup子系统
- 当前系统已挂载的cgroup信息
- cpu子系统
- cpu子系统练习
- 内存子系统
- memory子系统练习
- 删除cgroup
- Cgroups (Control Groups)是 Linux 下用于对一个或一组进程进行资源控制和监控的机制;
- 可以对诸如 CPU 使用时间、内存、磁盘 I/O 等进程所需的资源进行限制;
- 不同资源的具体管理工作由相应的 Cgroup 子系统(Subsystem)来实现 ;
- 针对不同类型的资源限制,只要将限制策略在不同的的子系统上进行关联即可 ;
- Cgroups 在不同的系统资源管理子系统中以层级树(Hierarchy)的方式来组织管理:每个Cgroup 都可以包含其他的子 Cgroup,因此子 Cgroup 能使用的资源除了受本 Cgroup 配置的资源参数限制,还受到父Cgroup 设置的资源限制 。
cgroups 主要提供了如下功能
- 资源限制: 限制资源的使用量,例如我们可以通过限制某个业务的内存上限,从而保护主机其他业务的安全运行。
- 优先级控制:不同的组可以有不同的资源( CPU 、磁盘 IO 等)使用优先级。
- 审计:计算控制组的资源使用情况。
- 控制:控制进程的挂起或恢复。
cgroups功能的实现依赖于三个核心概念:子系统、控制组、层级树。
-
子系统(subsystem):是一个内核的组件,一个子系统代表一类资源调度控制器。例如内存子系统可以限制内存的使用量,CPU 子系统可以限制 CPU 的使用时间。
-
控制组(cgroup):表示一组进程和一组带有参数的子系统的关联关系。例如,一个进程使用了 CPU 子系统来限制 CPU 的使用时间,则这个进程和 CPU 子系统的关联关系称为控制组。
-
层级树(hierarchy):是由一系列的控制组按照树状结构排列组成的。这种排列方式可以使得控制组拥有父子关系,子控制组默认拥有父控制组的属性,也就是子控制组会继承于父控制组。比如,系统中定义了一个控制组 c1,限制了 CPU 可以使用 1 核,然后另外一个控制组 c2 想实现既限制 CPU 使用 1 核,同时限制内存使用 2G,那么 c2 就可以直接继承 c1,无须重复定义 CPU 限制。
cgroups 的三个核心概念中,子系统是最核心的概念,因为子系统是真正实现某类资源的限制的基础。
Linux内核代码中Cgroups的实现进程数据结构
struct task_struct
{
#ifdef CONFIG_CGROUPS
// 设置这个进程属于哪个css_set
struct css_set __rcu *cgroups;
// cg_list是用于将所有同属于一个css_set的task连成一起
struct list_head cg_list;
#endif
}
css_set 是 cgroup_subsys_state 对象的集合数据结构
struct css_set {
struct cgroup_subsys_state *subsys[CGROUP_SUBSYS_COUNT];
};
cgroup子系统
- cpu 子系统,主要限制进程的 cpu 使用率。
- cpuacct 子系统,可以统计 cgroups 中的进程的 cpu 使用报告。
- cpuset 子系统,可以为 cgroups 中的进程分配单独的 cpu 节点或者内存节点。
- memory 子系统,可以限制进程的memory 使用量。
- blkio 子系统,可以限制进程的块设备 io。
- devices 子系统,可以控制进程能够访问某些设备。
- net_cls 子系统,可以标记 cgroups 中进程的网络数据包,然后可以使用 tc 模块(traffic control)对数据包进行控制。
- net_prio — 这个子系统用来设计网络流量的优先级
- freezer 子系统,可以挂起或者恢复cgroups 中的进程。
- ns 子系统,可以使不同 cgroups 下面的进程使用不同的 namespace
- hugetlb —这个子系统主要针对于HugeTLB系统进行限制,这是一个大页文件系统。
# mount -t cgroup cgroup on /sys/fs/cgroup/systemd type cgroup (rw,nosuid,nodev,noexec,relatime,seclabel,xattr,release_agent=/usr/lib/systemd/systemd-cgroups-agent,name=systemd) cgroup on /sys/fs/cgroup/net_cls,net_prio type cgroup (rw,nosuid,nodev,noexec,relatime,seclabel,net_prio,net_cls) cgroup on /sys/fs/cgroup/pids type cgroup (rw,nosuid,nodev,noexec,relatime,seclabel,pids) cgroup on /sys/fs/cgroup/freezer type cgroup (rw,nosuid,nodev,noexec,relatime,seclabel,freezer) cgroup on /sys/fs/cgroup/perf_event type cgroup (rw,nosuid,nodev,noexec,relatime,seclabel,perf_event) cgroup on /sys/fs/cgroup/memory type cgroup (rw,nosuid,nodev,noexec,relatime,seclabel,memory) cgroup on /sys/fs/cgroup/cpuset type cgroup (rw,nosuid,nodev,noexec,relatime,seclabel,cpuset) cgroup on /sys/fs/cgroup/devices type cgroup (rw,nosuid,nodev,noexec,relatime,seclabel,devices) cgroup on /sys/fs/cgroup/hugetlb type cgroup (rw,nosuid,nodev,noexec,relatime,seclabel,hugetlb) cgroup on /sys/fs/cgroup/cpu,cpuacct type cgroup (rw,nosuid,nodev,noexec,relatime,seclabel,cpuacct,cpu) cgroup on /sys/fs/cgroup/blkio type cgroup (rw,nosuid,nodev,noexec,relatime,seclabel,blkio)cpu子系统
- cpu.shares: 可出让的能获得 CPU 使用时间的相对值。
- cpu.cfs_period_us:cfs_period_us 用来配置时间周期长度,单位为 us(微秒)。
- cpu.cfs_quota_us:cfs_quota_us 用来配置当前 Cgroup 在 cfs_period_us 时间内最多能使用的 CPU 时间数,单位为 us(微秒)。
- cpu.stat : Cgroup 内的进程使用的 CPU 时间统计。
- nr_periods : 经过 cpu.cfs_period_us 的时间周期数量。
- nr_throttled : 在经过的周期内,有多少次因为进程在指定的时间周期内用光了配额时间而受到限制。
- throttled_time : Cgroup 中的进程被限制使用 CPU 的总用时,单位是 ns(纳秒)。
1、在cgroup cpu子系统下创建目录
cd /sys/fs/cgroup/cpu mkdir cpudemo
执行完上述命令后,我们查看一下我们新创建的目录下发生了什么?
# ls -l /sys/fs/cgroup/cpu/cpudemo total 0 -rw-r--r--. 1 root root 0 Oct 7 16:09 cgroup.clone_children --w--w--w-. 1 root root 0 Oct 7 16:09 cgroup.event_control -rw-r--r--. 1 root root 0 Oct 7 16:09 cgroup.procs -r--r--r--. 1 root root 0 Oct 7 16:09 cpuacct.stat -rw-r--r--. 1 root root 0 Oct 7 16:09 cpuacct.usage -r--r--r--. 1 root root 0 Oct 7 16:09 cpuacct.usage_percpu -rw-r--r--. 1 root root 0 Oct 7 16:09 cpu.cfs_period_us -rw-r--r--. 1 root root 0 Oct 7 16:09 cpu.cfs_quota_us -rw-r--r--. 1 root root 0 Oct 7 16:09 cpu.rt_period_us -rw-r--r--. 1 root root 0 Oct 7 16:09 cpu.rt_runtime_us -rw-r--r--. 1 root root 0 Oct 7 16:09 cpu.shares -r--r--r--. 1 root root 0 Oct 7 16:09 cpu.stat -rw-r--r--. 1 root root 0 Oct 7 16:09 notify_on_release -rw-r--r--. 1 root root 0 Oct 7 16:09 tasks
由上可以看到我们新建的目录下被自动创建了很多文件,其中 cpu.cfs_quota_us 文件代表在某一个阶段限制的 CPU 时间总量,单位为微秒。例如,我们想限制某个进程最多使用 1 核 CPU,就在这个文件里写入 100000(100000 代表限制 1 个核) ,tasks 文件中写入进程的 ID 即可(如果要限制多个进程 ID,在 tasks 文件中用换行符分隔即可)。
2、创建进程,加入cgroup
使用以下命令将 shell 进程加入 cgroup 中:
# cd /sys/fs/cgroup/cpu/mydocker # echo $$ > tasks
查看一下 tasks 文件内容:
# cat tasks 4924 5008
3、执行 CPU 耗时任务,验证 cgroup 是否可以限制 cpu 使用时间
执行完上述命令后,我们新打开一个 shell 窗口,使用 top -p 命令查看当前 cpu 使用率,-p 参数后面跟进程 ID,我这里是 4924
# top -p 4924 top - 16:19:45 up 10:27, 2 users, load average: 1.67, 0.50, 0.21 Tasks: 1 total, 1 running, 0 sleeping, 0 stopped, 0 zombie %Cpu(s): 34.2 us, 12.8 sy, 0.0 ni, 52.5 id, 0.0 wa, 0.0 hi, 0.5 si, 0.0 st KiB Mem : 3880256 total, 2901232 free, 478524 used, 500500 buff/cache KiB Swap: 2097148 total, 2097148 free, 0 used. 3158040 avail Mem PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND 4924 root 20 0 15920 2864 1796 R 98.3 0.1 1:04.15 bash
此时,该进程消耗完一个cpu
4、限制进程使用cpu为0.5核
# top -p 4924 top - 16:19:45 up 10:27, 2 users, load average: 1.67, 0.50, 0.21 Tasks: 1 total, 1 running, 0 sleeping, 0 stopped, 0 zombie %Cpu(s): 34.2 us, 12.8 sy, 0.0 ni, 52.5 id, 0.0 wa, 0.0 hi, 0.5 si, 0.0 st KiB Mem : 3880256 total, 2901232 free, 478524 used, 500500 buff/cache KiB Swap: 2097148 total, 2097148 free, 0 used. 3158040 avail Mem PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND 4924 root 20 0 15920 2864 1796 R 50 0.1 1:04.15 bash
此时,该进程使用的cpu使用率为50%
内存子系统- memory.usage_in_bytes : cgroup 下进程使用的内存,包含 cgroup 及其子 cgroup 下的进程使用的内存
- memory.max_usage_in_bytes : cgroup 下进程使用内存的最大值,包含子 cgroup 的内存使用量。
- memory.limit_in_bytes : 设置 Cgroup 下进程最多能使用的内存。如果设置为 -1,表示对该 cgroup 的内存使用不做限制。
- memory.oom_control : 设置是否在 Cgroup 中使用 OOM(Out of Memory)Killer,默认为使用。当属于该 cgroup 的进程使用的内存超过最大的限定值时,会立刻被 OOM Killer 处理。
1、memory子系统目录中创建目录结构
cd /sys/fs/cgroup/memory mkdir memorydemo # 创建该目录后,会生成一些控制文件
限制该cgroup使用内存为1G
echo 1073741824 > memory.limit_in_bytes
2、创建进程,加入 cgroup
把当前 shell 进程 ID 写入 tasks 文件内:
复制代码 # cd /sys/fs/cgroup/memory/memorydemo # echo $$ > tasks
3、使用内存压测工具,模拟内存溢出
memtester压测,限制1500M内存导致进程被Kill
# memtester 1500 1 memtester version 4.5.0 (64-bit) Copyright (C) 2001-2020 Charles Cazabon. Licensed under the GNU General Public License version 2 (only). pagesize is 4096 pagesizemask is 0xfffffffffffff000 want 1500MB (1572864000 bytes) got 1500MB (1572864000 bytes), trying mlock ...Killed删除cgroup
直接删除创建的文件夹即可
rmdir /sys/fs/cgroup/memory/memorydemo/



