深入浅出理解Cgroup

Cgroup(Control Groups)是linux内核用来控制系统资源的机制,它将操作系统中的所有进程以组为单位划分,给这一组进程定义对某一类资源特定的访问权限。Cgroup用子系统(subsystem)来描述所能控制的系统资源,子系统具有多种类型,每个类型的子系统都代表一种系统资源,比如freezer、CPU、memory、IO等。以freezer子系统为例,这个子系统可以对一组线程批量冻结,使用下面命令将打开freezer子系统:mount cgroup none /dev/freezer freezer。

该命令将子系统挂载于/dev/freezer目录,接下来可以在/dev/freezer目录下创建若干个目录,例如目录top、background,每个目录代表一组线程的资源分配行为,以cgroup实例描述,那么多级的目录以cgroup实例的形式组成了一个树形结构。接下来,可以给top组或者background组配置组内进程,

echo 1199 > /dev/freezer/top/cgroup.procs

当前cgroup版本已经不支持同一进程组内不同线程分属于子系统内不同cgroup。配置完top组内的线程后,可以通过操作freezer.state节点配置组内所有线程冻结:

echo FROZEN > /dev/freezer/top/freezer.state

解冻组内所有线程:

echo THAW > /dev/freezer/top/freezer.state

Cgroup关键数据结构以及相互关系

Cgroup子系统以cgroup_subsys结构体描述,子系统中每个目录由cgroup结构体描述,这个目录维护了一组线程的资源访问属性。子系统的cgroup_subsys结构体通过cgroup_root结构体与子系统根目录的cgroup建立联系。目录之间的树形结构通过cgroup结构体中的cgroup_subsys_state结构体描述,cgroup_subsys_state结构体中有指向父目录的parent 指针、以及兄弟和孩子链表。如图:

Cgroup关键数据结构以及相互关系

由于线程与cgroup目录具有多对多的关系,即一个cgroup目录中含有多个线程,一个线程属于不同子系统中的多个cgroup。linux通过css_set结构体以及cgrp_cset_link结构体来描述这个多对多的关系。css_set结构代表一组线程,这些线程在各个子系统内属于同一cgroup目录;cgrp_cset_link代表一个css_set和一个cgroup的映射关系,cgroup有一个cgrp_cset_link链表,通过这个链表可以找到这个 cgroup目录下所有线程组成的css_set,同样,css_set也维护一个cgrp_cset_link链表,通过这个链表,可以找到这个css_set在各个子系统中所归属的cgroup。如下图css_set Z下的所有线程属于freezer子系统的cgroupA以及memory子系统的cgroupC, css_set X下的所有线程属于freezer子系统的cgroupA:

Cgroup关键数据结构以及相互关系

cgroup核心逻辑

当某个子系统被挂载使能后,系统中所有线程默认处于子系统根目录所代表的cgroup实例中。

配置task到目标cgroup

用户或者应用程序通过往cgroup.procs节点写入pid,cgroup.procs节点的write函数对应到cgroup_procs_write。

配置task到目标cgroup

cgroup_kn_lock_live函数根据当前节点目录解析到该目录所对应的cgroup实体,通过写权限检查以后,进入到主逻辑cgroup_attach_task函数里。

配置task到目标cgroup

cgroup_migrate_prepare_dst函数保存当前task所在css_set结构,

cgroup_migrate_prepare_dst函数利用保存的当前css_set,查找是否存在满足条件的目标css_set,如果不存在满足条件的目标css_set,则创建一个新的css_set,插入多对多二维关系链表中。接下来cgroup_migrate函数将task从源css_set迁移到目标css_set中。

操控cgroup属性

以freezer子系统为例,通过freezer.state节点控制cgroup组的冻结与解冻,这个节点对应到freezer_write函数,实际的逻辑在freezer_change_state函数中。

操控cgroup属性

freezer_change_state函数第一个参数属于freezer结构体,它通过内嵌的cgroup_subsys_state结构与cgroup关联,也就是说每个freezer结构体直接对应到freezer子系统的一个目录。接下来看函数逻辑,css_for_each_descendant_pre循环体里对当前目录以及每个子孙目录所代表cgroup实体执行freezer_apply_state函数。freezer_apply_state函数通过调用freeze_cgroup和unfreeze_cgroup函数实际操作cgroup内每个task的冻结与解冻。

Cgroup小结

cgroup除了实现了freezer子系统,还实现了控制组IO调度的blkio cgroup、控制cpu核资源组分配的cpuset cgroup、控制cpu运行时间组分配的cpu cgroup、控制memory组分配的momory cgroup以及控制网络带宽组分配的cls_net cgroup,相关代码读者可自行研究。

参考资料:

1.https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/tree/kernel/cgroup/cgroup.c?h=v5.4.143

2.https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/tree/kernel/cgroup/legacy_freezer.c?h=v5.4.143

3.https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/tree/kernel/cgroup/freezer.c?h=v5.4.143

Camera课程

Python教程

Java教程

Web教程

数据库教程

图形图像教程

办公软件教程

Linux教程

计算机教程

大数据教程

开发工具教程

Android进程相关