本文作为cgroup内核代码的开篇文档,只介绍cgroup的设计理念,不介绍具体代码。理解了本文即理解了cgroup的核心思想,可以更容易地理解其它cgroup的源码分析文章。文中出现的内核源码来源于4.14.4版本。
一、资源的树型管理
CGROUP是拥有共同资源属性的任务的集合,用来控制一组任务拥有多少资源可用。内核中有多种资源(称为子系统,参考struct cgroup_subsys和
参考struct cgroup_subsys_state),这些资源绝大多数是可数、可分配的,因此CGROUP V1版本中是以层次树(也叫
hierarchy)的方式来进行管理。因为树的子树或子节点
(参考struct cgroup)属性可以体现资源的包含或子集关系。比如根节点拥有全部的资源上限(如内存2G),子节点拥有部分的资源上限(如内存1G)。任务挂到哪个节点上,就有相应的资源控制属性。
为了简化或者减少数据结构,可以把多个资源放到一颗树上进行管理,因此cgroup这个对象可以同时管理多个资源(subsys),可以看到它有一个
cgroup_subsys_state数组成员用来保存这个节点中的多种资源当时的状态。
二、统计任务资源
当一个任务分配资源(如内存malloc后产生的缺页)时,需要把分配的资源统计到cgroup的节点上。因此需要从task_struct对象访问到cgroup_subsys_state状态对象。task_struct的cgroups成员(css_set对象,即资源状态的集合对象)保存了和这个任务相关的所有cgroup_subsys_state状态的数组。这样,每个任务消费了资源,就可以通过该成员进行统计。
但是每个任务的cgroup成员所指向的css_set对象是不同的。有的任务限制CPU,有的任务限制内存。只有那些有相同限制类别的任务会指向相同的css_set对象(比如某容器内的task通常指向同一个css_set对象)。
三、从cgroup获取任务列表
反过来,当需要从cgroup来遍历它里面的task的需求。一种方式是把拥有相同资源层次树hierarchy的任务都链接到cgroup上。但是任务有可能同时存在于多个hierarchy中(拥有多种资源)。在task_struct中增加一个list_head不够,增加多个list_head不现实。因此一个任务可能存在多个cgroup中(不同hierarchy),一个cgroup又有多个任务。task和cgroup是多对多的关系。对于这种多对多关系的对象,可以设计一种中间结构体A,当某task和某个cgroup进行匹配时,就创建一个A对象。A对象分别指针指回关联的task和cgroup。在cgroup中将和它相关的A对象链接起来,遍历这个链表,就可以遍历在该group中的所有task。如果某task T在两个cgroup中,则有两个A对象分别指向T,这两个A对象分别链入两个cgroup的链表。这样两个cgroup能够遍历访问到不同的A对象和T。
实际上内核设计将上述思想做了进一步的优化。由于多个任务拥有一个公共的css_set对象上,因此内核就将任务链入css_set的task链表(css_set的tasks成员)。而让css_set与cgroup形成多对多的关系,因此css_set和cgroup是一个多对多的关系。struct cgrp_cset_link就css_set与cgroup多对多匹配的中间结构。采用css_set(比采用task)与cgroup进行匹配,可以减少很多中间结构。css_set与cgroup的多对多的关系图,请参考我的另外一篇文章(http://blog.chinaunix.net/uid-93067-id-3309752.html)。从cgroup遍历task时,先遍历中间的cgrp_cset_link对象,然后通过cgrp_cset_link访问相关的css_set对象,然后再遍历css_set的所有task。
四、cgroup V2
可以看到,CGROUP V1的多层hierarchy的支持,是css_set与cgroup多对多关系以及cgrp_cset_link的复杂性根源。因此在4.X的内核版本,社区实现了一个unified hierarchy(只有一个层级的hierarchy)的简化版的CGROUP V2。
阅读(1741) | 评论(0) | 转发(0) |