基本概念
namespace:隔离进程组之间的资源
cgroup:对一组进程进行统一的资源监控和限制,进程按组进行管理的机制
cgroup 的构成:
- subsystem:对应内核模块,用于对进程组进行操作。
- hierarchy:一棵 cgroup 树,用于进程分组。
其他:
- 在任意一个 hierarchy 内包含 linux 系统的所有 process。
- 在同一个 hierarchy 内,process 属于唯一的 process group。但 process 可以存在于不同的 hierarchy 中。
- hierarchy 会对应若干不同的 subsystem(可以为 0),一个 subsystem 只能关联一个 hierarchy。systemd 没有对应的 subsystem。
process -> process group(cgroup) -> hierarchy
树节点 -> 树
Subsystem
subsystem name
subsystem 关联 hierarchy id:如果为 0,无绑定/cgroup v2 绑定/未被内核开启
num of cgroups:关联 hierarchy 内进程组个数
enabled:是否开启,通过内核参数 cgroup_disable 调整
详细
cpu (since Linux 2.6.24; CONFIG_CGROUP_SCHED)
用来限制 cgroup 的 CPU 使用率。
cpuacct (since Linux 2.6.24; CONFIG_CGROUP_CPUACCT)
统计 cgroup 的 CPU 的使用率。
cpuset (since Linux 2.6.24; CONFIG_CPUSETS)
绑定 cgroup 到指定 CPUs 和 NUMA 节点。
memory (since Linux 2.6.25; CONFIG_MEMCG)
统计和限制 cgroup 的内存的使用率,包括 process memory, kernel memory, 和 swap。
devices (since Linux 2.6.26; CONFIG_CGROUP_DEVICE)
限制 cgroup 创建(mknod)和访问设备的权限。
freezer (since Linux 2.6.28; CONFIG_CGROUP_FREEZER)
suspend 和 restore 一个 cgroup 中的所有进程。
net_cls (since Linux 2.6.29; CONFIG_CGROUP_NET_CLASSID)
将一个 cgroup 中进程创建的所有网络包加上一个 classid 标记,用于 tc 和 iptables。 只对发出去的网络包生效,对收到的网络包不起作用。
blkio (since Linux 2.6.33; CONFIG_BLK_CGROUP)
限制 cgroup 访问块设备的 IO 速度。
perf_event (since Linux 2.6.39; CONFIG_CGROUP_PERF)
对 cgroup 进行性能监控
net_prio (since Linux 3.3; CONFIG_CGROUP_NET_PRIO)
针对每个网络接口设置 cgroup 的访问优先级。
hugetlb (since Linux 3.5; CONFIG_CGROUP_HUGETLB)
限制 cgroup 的 huge pages 的使用量。
pids (since Linux 4.3; CONFIG_CGROUP_PIDS)
限制一个 cgroup 及其子孙 cgroup 中的总进程数。
使用
1 | # 挂载一颗和cpuset subsystem关联的cgroup树到/sys/fs/cgroup/cpuset |
查看进程对应的 cgroup
proc/[pid]/cgroup
hierarchy id : subsystems : 进程在 hierarchy 中的相对路径
创建管理 cgroup
cgroup 目录
- cgroup.clone_children
这个文件只对 cpuset subsystem 有影响,当该文件的内容为 1 时,新创建的 cgroup 将会继承父 cgroup 的配置,即从父 cgroup 里面拷贝配置文件来初始化新 cgroup,可以参考这里 - cgroup.procs
当前 cgroup 中的所有进程 ID,系统不保证 ID 是顺序排列的,且 ID 有可能重复 - cgroup.sane_behavior
具体功能不详,可以参考这里和这里 - notify_on_release
该文件的内容为 1 时,当 cgroup 退出时(不再包含任何进程和子 cgroup),将调用 release_agent 里面配置的命令。新 cgroup 被创建时将默认继承父 cgroup 的这项配置。 - release_agent
里面包含了 cgroup 退出(移出)时将会执行的命令,系统调用该命令时会将相应 cgroup 的相对路径当作参数传进去。 注意:这个文件只会存在于 root cgroup 下面,其他 cgroup 里面不会有这个文件。 - tasks
当前 cgroup 中的所有线程 ID,系统不保证 ID 是顺序排列的
创建子 cgroup
新建子文件夹
添加进程
- 在一颗 cgroup 树里面,一个进程必须要属于一个 cgroup。
- 新创建的子进程将会自动加入父进程所在的 cgroup
- 从一个 cgroup 移动一个进程到另一个 cgroup 时,只要有目的 cgroup 的写入权限就可以了,系统不会检查源 cgroup 里的权限。
- 用户只能操作属于自己的进程,不能操作其他用户的进程,root 账号除外
打印当前 shell pid
echo $$
1 | sh -c 'echo 1421 > ../cgroup.procs' |
将 pid 写入,即是进程加入 cgroup。pid 不可在文件中删除,只可以被转移。因为 在一颗 cgroup 树里面,一个进程必须要属于一个 cgroup
Pid Subsystem
pids.current: 表示当前 cgroup 及其所有子孙 cgroup 中现有的总的进程数量
pids.max: 当前 cgroup 及其所有子孙 cgroup 中所允许创建的总的最大进程数量
通过写入 pids.max 限制成功
- 子孙 cgroup 中的 pids.max 大小不能超过父 cgroup 中的大小
- 子 cgroup 中的进程数不仅受自己的 pids.max 的限制,还受祖先 cgroup 的限制
pids.current > pids.max 出现的情况:
- 设置 pids.max 时,将其值设置的已经比 pids.current 小
- pids.max 只会在当前 cgroup 中的进程 fork、clone 的时候生效,将其他进程加入到当前 cgroup 时,不会检测 pids.max
Memory Subsystem
1 | cgroup.event_control #用于eventfd的接口 |
设置了内存限制立即生效 –> 物理内存使用量达到 limit –> memory.failcnt +1 –> 内核会尽量将物理内存中的数据移到 swap 空间上去 –> 设置的 limit 过小,或者 swap 空间不足 –> kill 掉 cgroup 内继续申请内存的进程(默认行为)
详细链接
##
CPU Subsystem
cfs_period_us:时间周期长度
cfs_quota_us:在一个周期长度内所能使用的 CPU 时间数
cpu.shares:
- 针对所有的 CPU 的相对值,默认值是 1024
- 仅在 CPU 忙时起作用
- 无法精确的控制 CPU 使用率,因为 cgroup 会动态变化
limit_in_cores = cfs_period_us / cfs_quota_us