概念
多层级 multi-hierarchy
挂载一个 cgroup controller 到一个目录后,这个目录就成了一个 cgroup hierarchy
一个 cgroup hierarchy 下可以创建多个子目录,而每个字目录也都是一个子 hierarchy,二者构成「父子 cgroup 关系」,父 cgroup 的限制会同时应用于任何子 cgroup
但需要注意的是,每个 cgroup 的 cgroup.procs 和 tasks 只显示直接属于该 cgroup 的进程 / 线程而不会显示子 cgroup 中的进程 / 线程
cgroup.procs/tasks 文件
cgroup.procs 为 cgroup 管理的进程、tasks 为 cgroup 管理的线程
添加一个进程到 cgroup 时只需将它的 pid 加入到对应 cgroup hierchy 的 cgroup.procs 文件中即可
当存在多个组 group 时,一个进程只能存在于一个 group 中,把它加入到一个 group 会自动将它从其他 group 中移出
将一个进程加入至 cgroup.procs 文件时,会自动将它的所有子进程也加入、同时会自动将它的所有子线程加入 tasks 中
将一个线程(或进程)加入至 tasks 文件时,只会将这个线程(或进程的主线程)加入,它所属的进程、所属的进程的其他子线程均不会进入
注意,将线程加入至 tasks 文件时,是可以在 cgroup.procs 文件中看到这个线程所属的父进程的 pid 的,但是进程本身不受管理、且在 tasks 文件中也看不到进程的 id
从 cgroup 中移除任务
任何一个进程都会存在于 exactly 一个 cgroup 中
因此,不存在实际上的「移除」任务 —— 只能将任务移动到其他 cgroup —— 当然我们理解的删除往往就是移动到 root
named cgroup hierarchy
在 cgroups v1 中,可以利用如下命令挂载一个没有 controller 的 cgroup hierarchy(称为 named cgroup hierarchy)
mount -t cgroup -o none,name=somename none /some/mount/point
这个 cgroup hierarchy 存在的唯一目的是跟踪进程(而不是管理进程);例如 systemd 便使用了这个能力
cgroup controller (subsystem)
cpu
cpu.shares
一个相对值(默认 1024),这个进程会被分配 指定的值 / 全局总值 这么多的 CPU 时间比例;因此,这个值用来调整一个任务占用 CPU 时间的权重而不是绝对的占用多少
另外,这个配置仅在繁忙时生效 —— 这指定的是可被分配到的 cpu shares 的最小值 —— 如果 CPU 本不繁忙则不会有限制
cpu.cfs_perios_us / cpu.cfs_quota_us / cpu.cfs_burst_us
cpu.cfs_period_us :周期的时间长度(微秒),后续所有配置都是相对于「这一个周期内」的限制;默认为 100_000(100ms)(最高可设置成 1s)
cpu.cfs_quota_us 一个周期内进程可使用的最大 CPU 时间(微秒),默认 -1 不限制,最少可设置成 1ms
cpu.cfs_burst_us 允许累积历史未使用的 CPU 时间供后续超出 quota 使用,这个配置指定可以累积的上限,默认为 0 不可累积
cpu.stat
包含给定 cgroup 的 CPU 统计值,类似
nr_periods 0 nr_throttled 0 throttled_time 0 nr_bursts 0 burst_time 0
nr_periods: 已经过的 period 数量
nr_throttled: 被限制的次数
throttled_time: 被限制的总时间(以纳秒为单位)。
nr_bursts: 发生突发的 period 数量
burst_time: 共突发超额使用的累计 wall-time(以纳秒为单位)。
cpu.rt…
cpuacct
cpuset
memory
devices
freezer
注:freezer 在 root cgroup 不存在,必须创建子 cgroup hierarchy 来使用
freezer.state
freezer.state 是 freezer controller 唯一一个可读写的文件,用于查看和控制 freeze 的状态
设置时,可以设置为
THAWED - 解冻,即取消冻结(默认)
FROZEN - 冻结,即暂停所有进程的执行
在读取时,除了上面的两个状态,还有
FREEZING - 一个中间状态,在进程从未冻结转换为冻结态时会出现
另外,由于父 cgroup 同时会影响下层 cgroup,因此如果任何父级指定了 FROZEN 则为该 cgroup 始终为冻结状态
freezer.parent_freezing / freezer.self_freezing
0 - 未冻结,1 - 已冻结
freezer.state 在读取时读到的始终是「当前 cgroup 的实际冻结状态」,而这个会受本身是否冻结和父级是否冻结同时影响
freezer.parent_freezing 用于描述父级是否冻结、freezer.self_freezing 用于描述本级是否冻结
换句话说,在不考虑 FREEZING 状态的情况下,如果这两个文件任一为 1 则 freezer.state 为 FROZEN、如果这两个文件全为 0 则 freezer.state 为 THAWED