cgroup是一个内核的功能,他的作用是将系统中的进程进行分组化管理。docker、openshift就是基于cgroup上建立的。
相关概念
task 一个任务就是一个进程
control group 就是一个进程集合,可以把它理解成一个房间,每个房间都是相互隔离的。
hierachy(层级) control group存在父子的概念,负责可以使用子组里的资源
subsystem 如果组内的进程需要工作,就必须要有cpu内存之类的资源,这就需要涉及到资源控制器,这个资源控制器就是subsystem。比如一个cpu控制器就是一个subsystem
cgroup结构
一个层级可以有多个子系统,比如cpu、内存等,但是一个子系统只能附在一个层级上
子组可以继承父组
cgroup设计原理
#ifdef CONFIG_CGROUPS /* Control Group info protected by css_set_lock */ struct css_set *cgroups; /* cg_list protected by css_set_lock and tsk->alloc_lock */ struct list_head cg_list; #endif
cgroup作为指针指向css_set(用于存放与进程有关的cgroup信息)
list_head用于将同一个css_set的进程组织成链表
struct css_set { atomic_t refcount; struct hlist_node hlist; struct list_head tasks; struct list_head cg_links; struct cgroup_subsys_state *subsys[CGROUP_SUBSYS_COUNT]; struct rcu_head rcu_head; };
refcount是css_set的引用计数,组里加一个进程,refcount加1
hlist把css_set组织成hash表,使内核可以快速查找特定的css_set。
tasks指向所有连到此 css_set 的进程连成的链表。
cg_links 指向一个由 struct_cg_cgroup_link 连成的链表。
Subsys 是一个指针数组,存储一组指向 cgroup_subsys_state 的指针。
一个 cgroup_subsys_state 就是进程与一个特定子系统相关的信息。通过这个指针数组,进程就可以获得相应的 cgroups 控制信息了。以此就可以限制进程使用资源了。
task_struct->css_set->cgroup_subsys_state->cgroup。
struct cgroup { unsigned long flags; atomic_t count; struct list_head sibling; struct list_head children; struct cgroup *parent; struct dentry *dentry; struct cgroup_subsys_state *subsys[CGROUP_SUBSYS_COUNT]; struct cgroupfs_root *root; struct cgroup *top_cgroup; struct list_head css_sets; struct list_head release_list; struct list_head pidlists; struct mutex pidlist_mutex; struct rcu_head rcu_head; struct list_head event_list; spinlock_t event_list_lock; };
sibling,children 和 parent负责层级的划分
一个进程对应一个css_set,一个css_set存储了一组进程跟各子系统相关的信息。
我们创建一个层级 A,A 上面附加了 cpu 和 memory 两个子系统,进程 B 属于 A 的根 cgroup;然后我们再创建一个层级 C,C 上面附加了 ns 和 blkio 两个子系统,进程 B 同样属于 C 的根 cgroup;那么进程 B 对应的 cpu 和 memory 的信息是从 A 的根 cgroup 获得的,ns 和 blkio 信息则是从 C 的根 cgroup 获得的。
struct cgroupfs_root { struct super_block *sb; unsigned long subsys_bits; int hierarchy_id; unsigned long actual_subsys_bits; struct list_head subsys_list; struct cgroup top_cgroup; int number_of_cgroups; struct list_head root_list; unsigned long flags; char release_agent_path[PATH_MAX]; char name[MAX_CGROUP_ROOT_NAMELEN]; };
sb 指向该层级关联的文件系统数据块。
subsys_bits 和 actual_subsys_bits 分别指向将要附加到层级的子系统和现在实际附加到层级的子系统,在子系统附加到层级时使用。
top_cgroup 指向该层级的根 cgroup。number_of_cgroups 记录该层级 cgroup 的个数。
root_list 是一个嵌入的 list_head,用于将系统所有的层级连成链表。
struct cgroup_subsys { struct cgroup_subsys_state *(*create)(struct cgroup_subsys *ss, struct cgroup *cgrp); int (*pre_destroy)(struct cgroup_subsys *ss, struct cgroup *cgrp); void (*destroy)(struct cgroup_subsys *ss, struct cgroup *cgrp); int (*can_attach)(struct cgroup_subsys *ss, struct cgroup *cgrp, struct task_struct *tsk, bool threadgroup); void (*cancel_attach)(struct cgroup_subsys *ss, struct cgroup *cgrp, struct task_struct *tsk, bool threadgroup); void (*attach)(struct cgroup_subsys *ss, struct cgroup *cgrp, struct cgroup *old_cgrp, struct task_struct *tsk, bool threadgroup); void (*fork)(struct cgroup_subsys *ss, struct task_struct *task); void (*exit)(struct cgroup_subsys *ss, struct task_struct *task); int (*populate)(struct cgroup_subsys *ss, struct cgroup *cgrp); void (*post_clone)(struct cgroup_subsys *ss, struct cgroup *cgrp); void (*bind)(struct cgroup_subsys *ss, struct cgroup *root); int subsys_id; int active; int disabled; int early_init; bool use_id; #define MAX_CGROUP_TYPE_NAMELEN 32 const char *name; struct mutex hierarchy_mutex; struct lock_class_key subsys_key; struct cgroupfs_root *root; struct list_head sibling; struct idr idr; spinlock_t id_lock; struct module *module; };
从基本层次顺序定义上来看,由 task_struct、css_set、cgroup_subsys_state、cgroup、cg_cgroup_link、cgroupfs_root、cgroup_subsys 等结构体组成的 CGroup 可以基本从进程级别反应之间的响应关系。