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 可以基本从进程级别反应之间的响应关系。