2021-11-12 cgroup实现原理

目录

1.cgroup官方说明文档

2.全局数组cgroup_subsys[]

3.Cgroups原理 --很有用

Cgroups架构

添加cgroup subsystem/controller

例子:实现cephfs客户端io限流


1.cgroup官方说明文档

Cgroup内核文档翻译(3)——Documentation/cgroup-v1/cgroups.txt - Hello-World3 - 博客园

2.全局数组cgroup_subsys[]

cgroup中的cgroup_subsys[]数组解析_^_^-CSDN博客

全局数组cgroup_subsys[]在内核中应用很多,最常用的就是通过for_each_subsy()宏来遍历系统中的预定义的各个struct cgroup_subsys *ss:
#define for_each_subsys(ss, ssid)                    \
    for ((ssid) = 0; (ssid) < CGROUP_SUBSYS_COUNT &&        \
         (((ss) = cgroup_subsys[ssid]) || true); (ssid)++)

ss对像为cgroup_subsys对象就是对应cpu,freeze等对象,这里应该是root对象

    可以看到宏 "for_each_subsys"  就是遍历全局数组cgroup_subsys[]; 但是这个cgroup_subsys[]数组的各个元素是什么呢?它又在哪里定义的呢?
    说起来它还真的有点复杂,还是搞了那么些幺蛾子。它的定义在kernel/cgroup.c中:
/* generate an array of cgroup subsystem pointers */
#define SUBSYS(_x) [_x ## _cgrp_id] = &_x ## _cgrp_subsys,
static struct cgroup_subsys *cgroup_subsys[] = {
    #include <linux/cgroup_subsys.h>
};
#undef SUBSYS
    咦,奇怪,这个cgroup_subsys[]数组里面居然是一个头文件。编译器在编译的时候会展开头文件<linux/cgroup_subsys.h>:

...
SUBSYS(cpuset)
SUBSYS(cpu)
SUBSYS(cpuacct)
SUBSYS(io)
SUBSYS(memory)
SUBSYS(devices)
SUBSYS(freezer)
SUBSYS(net_cls)
SUBSYS(perf_event)
SUBSYS(net_prio)
SUBSYS(hugetlb)
SUBSYS(pids)
SUBSYS(debug)
.....
    为了更好的理解这个头文件内容,我去掉了一些边边角角,就得到上面的代码。即cgroup_subsys[]看起来有点像这样:
#define SUBSYS(_x) [_x ## _cgrp_id] = &_x ## _cgrp_subsys,
static struct cgroup_subsys *cgroup_subsys[] = {
    SUBSYS(cpuset)
    SUBSYS(cpu)
    SUBSYS(cpuacct)
    SUBSYS(io)
    SUBSYS(memory)
    SUBSYS(devices)
    SUBSYS(freezer)
    SUBSYS(net_cls)
    SUBSYS(perf_event)
    SUBSYS(net_prio)
    SUBSYS(hugetlb)
    SUBSYS(pids)
    SUBSYS(debug)
};
#undef SUBSYS
    我们还注意到"SUBSYS()" 在这里宏定义成了这个东西:
#define SUBSYS(_x) [_x ## _cgrp_id] = &_x ## _cgrp_subsys,
    将这个“SUBSYS”宏展开代入到cgroup_subsys[]中,看起来就是这样:
static struct cgroup_subsys *cgroup_subsys[] = {
    [cpuset_cgrp_id] = &cpuset_cgrp_subsys,
    [cpu_cgrp_id] = &cpu_cgrp_subsys,
    [cpuacct_cgrp_id] = &cpuacct_cgrp_subsys,
    [io_cgrp_id] = &_cgrp_subsys,
    [memory_cgrp_id] = &memory_cgrp_subsys,
    [devices_cgrp_id] = &devices_cgrp_subsys,
    [freezer_cgrp_id] = &freezer_cgrp_subsys,
    [net_cls_cgrp_id] = &net_cls_cgrp_subsys,
    [perf_event_cgrp_id] = &perf_event_cgrp_subsys,
    [net_prio_cgrp_id] = &net_prio_cgrp_subsys,
    [hugetlb_cgrp_id] = &_hugetlbcgrp_subsys,
    [pids_cgrp_id] = &pids_cgrp_subsys,
    [debug_cgrp_id] = &debug_cgrp_subsys,
};
    God,我们很接近真面目了,cgroup_subsys[]数组中的各个元素可以猜到就是&cpuset_cgrp_subsys,&cpuset_cgrp_subsys,&cpuacct_cgrp_subsys,&io_cgrp_subsys......这些就是cgroup中各个子系统cgroup_subsys的全局变量结构。这些xxx_cgrp_subsys全局变量在内核编译好后就已经初始化ok、分配好空间。
    我们拿cpu子系统struct cgroup_subsys cpu_cgrp_subsys这个结构来举例,它定义在kernel/sched/core.c文件中:

struct cgroup_subsys cpu_cgrp_subsys = {
    .css_alloc    = cpu_cgroup_css_alloc,
    .css_released    = cpu_cgroup_css_released,
    .css_free    = cpu_cgroup_css_free,
    .fork        = cpu_cgroup_fork,
    .can_attach    = cpu_cgroup_can_attach,
    .attach        = cpu_cgroup_attach,
    .legacy_cftypes    = cpu_files,
    .early_init    = 1,
};
    好了,说完了各个元素,我们再来说说数组中元素的index:"_x## _cgrp_id"。
    各个元素的索引"_x## _cgrp_id"也是通过SUBSY宏的把戏在include/linux/cgroup-defs.h中定义的:

/* define the enumeration of all cgroup subsystems */
#define SUBSYS(_x) _x ## _cgrp_id,
#define SUBSYS_TAG(_t) CGROUP_ ## _t, \
    __unused_tag_ ## _t = CGROUP_ ## _t - 1,
enum cgroup_subsys_id {
#include <linux/cgroup_subsys.h>
    CGROUP_SUBSYS_COUNT,
};
#undef SUBSYS_TAG
#undef SUBSYS
    有了前面对cgroup_subsys[]定义的分析,这里应该是轻车熟路了。即各个子系统的索引id "_x## _cgrp_id" 是通过枚举类型enum cgroup_subsys_id {} + <linux/cgroup_subsys.h> + SUBSYS(_x)宏来定义的。
    好了,这样以来,有了数组元素索引 和 数组元素,自然这个cgroup_subsys[]元素的定义也就终于真想大白了。

最后讲一点,为什么cgroup_subsys[]的定义要通过SUBSYS()宏 + "#include <linux/cgroup_subsys.h>" 的方式来定义呢?因为在内核中,有多个cgroup相关的结构都要用到子系统相关的名字的定义,如上面的xxx_cgrp_id以及xxx_cgrp_subsys等等。这样定义的好处就是提高了代码复用率,减少了重复代码。各种相关定义不用再写一长串,只需要短短几行就可以定义完成。
 

3.Cgroups原理 --很有用

Cgroups原理及其在CephFS io限流上的应用 技术指南

Cgroups的全称是Control
Groups,它是Linux内核提供的一种能够对cpu,内存等资源实现精细化控制的机制。本文介绍了它的原理以及其在CephFS io限流上的应用。

Cgroups架构

“Control Groups”的主要功能是将线程及其子线程分为多个组,以便对他们进行分别控制。其具体工作包括:

  • 将线程分组   --fork时自动
  • 为用户提供控制每组线程的操作接口(/sys/fs文件)  ---用户操作

每个control group关联一个cgroup subsystem(controller)。每个subsystem用于控制某项特殊的资源(如可以被调度的cpu核,内存使用总量等),subsystem之间可以存在依赖关系。目前linux默认会加载的subsystem包括:blkio、cpu、cpuacct、cpuset、devices、freezer、hugetlb、memory、net_cls、net_cls,net_prio、net_prio、perf_event、pids、systemd。

 

在内核中,cgroup会为每个/sys/fs/cgroup下的子目录(subsystem对应目录除外)创建一个css(cgroup_subsys_state)结构,该结构用于关联该目录对应的cgroup结构和所属的subsystem。每个内核线程的task结构中应一个css_set域,可以通过获取其中的css结构,获得其所属的control group信息。

Cgroup的代码实现大致可分为三部分

  1. 在系统启动时(start_kernel), 初始化cgroup_root,init_css_set(init线程的css_set), 各个subsystem;将cgroup_root挂载至/sys/fs/cgroup;
  2. 在线程fork时, 将父线程的css_set赋予子线程, 即:子线程继承父线程的css_set;
  3. 根据各subsystem需求,创建/sys/fs下的subsystem控制接口文件用户可以通过向这些文件写入数据实现对某个control group的控制,也可通过读取相应文件,获得当前该control group的状态。

添加cgroup subsystem/controller

添加一个子系统需要完成以下工作

1、实现一组cgroup要求subsystem实现的api,其中css_alloc和css_free是强制要求实现的,其余均可选;css_alloc用于分配cgroup_subsys_state结构所需的内存,用户可在该函数里初始化自己的subsystem,css_free用于卸载该subsystem时回收相应内存。

 

2、每个子系统拥有一个独立的自定义name,每个子系统需要定义一个struct cgroup_subsys类型的全局变量,该变量名为<name>_cgrp_subsys;将上面实现的cgroup subsystem api赋予变量相应的域

3、在 inclue/linux/cgroup_subsys.h里,添加属下entry

#if IS_ENABLED(CONFIG_CGROUP_XXX)

SUBSYS(<name>)

#endif

例子:实现cephfs客户端io限流

Cephfs客户端限流的目标:限制cephfs内核客户端元数据/数据操作速率(ops/byte per second)。目前我们采用的限流算法是令牌桶算法。

实现步骤如下:

1、添加include/linux/cgroup_cephfs.h头文件,定义cephfscg结构,其中包含cgroup_subsys_state域;同时定义其他所需类型(如令牌桶限流阀token_bucket_throttle)。

 

2、实现cgroup cephfs subsystem:

  • a)实现css_alloc和css_free函数;

  • b)定义cephfs
    subsystem的接口文件,其中meta_ops和data_ops用于设置元数据操作和数据操作令牌桶的更新周期,meta_ops.iops和data_ops.iops用于设置元数据/数据操作的iops限制,data_ops.band用于设置数据操作的吞吐量限制;除定位文件外,还需要设置这些文件的读写处理函数,这里所有读写操作均由cephfscg_set_throttle_params和cephfscg_throttle_params_read完成;

  • c)定义cephfs_cgrp_subsys变量;

  • d)在Include/linux/cgroup_subsys.h增加相应的entry。

3、在cephfs文件操作执行路径上增加相应的控制操作(获取当前task的css结构,并调用其对应的限流接口)。

 

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值