Skip to main content
 首页 » 操作系统

Linux Cgroup学习笔记

2022年07月19日181cloudgamer

一、cgroup学习

1.什么是Cgroup

Cgroups 是 control groups 的缩写,是 Linux 内核提供的一种可以限制、记录、隔离进程组(process groups)所使用的物理资源(如:cpu,memory,IO 等等)的机制。最初由 google 的工程师提出,后来被整合进 Linux 内核。Cgroups 也是 LXC 为实现虚拟化所使用的资源管理手段,可以说没有 cgroups 就没有 LXC。

2.Cgroup可以做什么

1.限制进程组可以使用的资源数量,限制进程最大使用的内存等。
2.进程组的优先级控制,比如为某个进程组分配特定的cpu share。
3.记录进程组使用的资源数量,比如记录某个进程CPU的使用时间。
4.进程组隔离,比如通过namespace以达到隔离的目的。
5.进程组控制,比如可以将进程组挂起或恢复。

3.Cgroup的模型

(1) 进程模型
在说Cgroup的模型之前,先回顾下进程模型,在linux系统上,所有的进程都有一个共同的父进程,叫做init进程,这个进程在内核启动的时候开始执行,然后通过init进程启动其他的进程,这些进程都是init的子进程。因为所有的进程都有一个共同的父进程。那么linux的进程模型就是一个单继承层次的模型,或者称之为树状模型。除此之外每一个linux进程但是除了init进程,都继承了一些环境变量(例如PATH环境变量)。
(2) Cgroup模型
Cgroup其实和进程类似,Cgroup也是继承体系,并且子Cgroup继承其父Cgroup的某些属性,两者最基本的差别在于,进程是单继承体系。而Cgroup可以存在多个不同的继承体系(就是可以有多个单继承体系,每个单继承体系互不影响)。

4.Cgroup的一些概念

在Cgroup中有这样四个概念,可以说理解了这四个概念,那么对于如何使用Cgroup:

Subsystems: 称之为子系统,一个子系统就是一个资源控制器,比如cpu子系统就是控制cpu时间分配的一个控制器。 
Hierarchies: 可以称之为层次体系,也可以称之为继承体系,指的是Control Groups是按照层次体系的关系进行组织的。 
Control Groups: 一组按照某种标准划分的进程。进程可以从一个Control Groups迁移到另外一个Control Groups中,同时Control Groups中的进程也会受到这个组的资源限制。 
Tasks: 在Cgroups中,Tasks就是系统的一个进程。

5.Subsystems

在Red_Hat_Enterprise_Linux-6系列的linux中,默认提供了如下子系统,功能如下:

blkio: 这个子系统为块设备设定输入/输出限制,比如物理设备(磁盘,固态硬盘,USB 等等) 。 
cpu: 这个子系统使用调度程序提供对 CPU 的 cgroup 任务访问。 
cpuacct: 这个子系统自动生成 cgroup 中任务所使用的 CPU 报告。 
cpuset: 这个子系统为 cgroup 中的任务分配独立 CPU(在多核系统)和内存节点。 
devices: 这个子系统可允许或者拒绝 cgroup 中的任务访问设备。 
freezer: 这个子系统挂起或者恢复 cgroup 中的任务。 
memory: 这个子系统设定 cgroup 中任务使用的内存限制,并自动生成由那些任务使用的内存资源报告。 
net_cls:这个子系统使用等级识别符(classid)标记网络数据包,可允许 Linux 流量控制程序(tc)识别从具体 cgroup 中生成的数据包。 
ns: 名称空间子系统。

Ubuntu中的目录是/sys/fs/cgroup, 但是高通的Android手机中这个目录下是空的,存在于/dev目录下,cgroup.rc指定了各个子系统的文件的路径

/dev/cgroup_info # strings cgroup.rc 
blkio:/dev/blkio 
cgroup2:/dev/cg2_bpf /dev/cpuctl 
cpuacct:/acct 
cpuset:/dev/cpuset //system-background、top-app也在这里面。 
freezer:/dev/freezer 
memory:/dev/memcg 
schedtune:/dev/stune

也可以# mount | grep cgroup 来查看都挂载在哪里了。

6.Tasks文件不仅可以读,还可以写,你将一个进程的进程号写入到某个cgroup目录下的tasks里面,你就将这个进程加入了相应的cgroup。

7.cgroup文件系统和VFS文件系统类似,cgroups的定义如下

struct file_system_type cgroup_fs_type = { 
    .name = "cgroup", 
    .mount = cgroup_mount, 
    .kill_sb = cgroup_kill_sb, //kill_sb释放超级块。 
    .fs_flags = FS_USERNS_MOUNT, 
};

8.Cgroup在kernel中的入口是:subsys_initcall(cgroup_sysfs_init); //msm-4.19\kernel\cgroup\cgroup.c

9.在cgroup文件系统中,对目录下的文件进行操作时,会调用struct kernfs_ops cgroup_kf_ops 结构体中指向的函数。比如:对文件进行读操作时,会调用 cgroup_file_read,在 cgroup_file_read 中,会根据需要调用该文件对应的 cftype 结构体定义的对应读函数。

cgroups通过实现cgroup文件系统来为用户提供管理cgroup的工具,而cgroup文件系统是基于Linux VFS实现的。相应地,cgroups为控制文件定义了相应的数据结构cftype,对其操作由cgroup文件系统定义的通过操作捕获,再调用cftype定义的具体实现。

cgroup中的每一个文件的后台动作都是 使用以空结尾的struct cftype数组来定义对cgroup文件进行操作时的后台动作,如 static struct cftype swap_files[] 通过模块初始化时执行cgroup_add_legacy_cftypes()添加到cgroup系统中,如 cgroup_add_legacy_cftypes(&memory_cgrp_subsys, memsw_cgroup_files)

10.Cgroup是将任意进程进行分组化管理的Linux内核功能。cgroup本身提供将进程进行分组化管理的功能和接口的基础结构。而后的Android操作系统也就凭借着这个技术,为每个应用程序分配不同的cgroup,将每个程序进行隔离,达到了一个应用程序不会影响其他应用程序环境的目的。

11.概念

task:一个进程。 
control group:控制族群,按照某种标准划分的进程组。 
hierarchy:层级,control group可以形成树形的结构,有父节点,子节点,每个节点都是一个control group,子节点继承父节点的特定属性。 
subsystem:子系统。子系统就是资源控制器,每种子系统就是一个资源的分配器,比如cpu子系统是控制cpu时间分配的。

可以使用lssubsys -al来列出系统支持多少种子系统,和使用ls /sys/fs/cgroup/(ubuntu)来显示已经挂载的子系统.

12.# mount | grep cgroup可以看挂载目录,到对应的挂载目录下,创建一个文件夹,就创建了一个control group了。
实验1:

/dev/freezer # mkdir mytest 
/dev/freezer # ls mytest/ 
cgroup.clone_children  cgroup.procs  freezer.parent_freezing  freezer.self_freezing  freezer.state  notify_on_release  tasks  yourtest 
/dev/freezer/mytest/ # echo $$ > tasks //当前shell进程就被设置进去了,之后更改属性文件的值可以对其进行设置。

实验2:

/dev/cpuset # mkdir mytest 
/dev/cpuset/mytest # echo "3" > cpus //使用CPU3 
/dev/cpuset/mytest # ps -A | grep system_server 
1772 
/dev/cpuset/mytest # echo 1772 > tasks

上面操作就将system_server线程绑定到CPU3上了。

实验3:

/dev/memcg # mkdir my_mem_ctl 
/dev/memcg/my_mem_ctl # ls 
cgroup.clone_children  memory.kmem.failcnt             memory.kmem.tcp.limit_in_bytes      memory.max_usage_in_bytes        memory.move_charge_at_immigrate  memory.swappiness 
cgroup.event_control   memory.kmem.limit_in_bytes      memory.kmem.tcp.max_usage_in_bytes  memory.memsw.failcnt             memory.oom_control               memory.usage_in_bytes 
cgroup.procs           memory.kmem.max_usage_in_bytes  memory.kmem.tcp.usage_in_bytes      memory.memsw.limit_in_bytes      memory.pressure_level            memory.use_hierarchy 
memory.failcnt         memory.kmem.slabinfo            memory.kmem.usage_in_bytes          memory.memsw.max_usage_in_bytes  memory.soft_limit_in_bytes       notify_on_release 
memory.force_empty     memory.kmem.tcp.failcnt         memory.limit_in_bytes               memory.memsw.usage_in_bytes      memory.stat                      tasks 
/dev/memcg/my_mem_ctl # echo $$ > tasks 
/dev/memcg/my_mem_ctl # echo 10M > memory.limit_in_bytes 
/dev/memcg/my_mem_ctl # cat memory.limit_in_bytes 
10485760

上面是限制当前shell进程最大使用10M内存。

相关文件解释:

memory.limit_in_bytes  显示当前内存(进程内存+页面内存)的使用量 
memory.memsw.usage_in_bytes  显示当前内存(进程内存+页面内存)+交换区的使用量 
memory.limit_in_bytes  设置、显示内存(进程内存+页面内存)使用量的限制值 
memory.memsw.limit_in_bytes  设置、显示内存(进程内存+页面内存)+交换区使用量的限制值 
memory.failcnt  显示当前内存(进程内存+页面内存)达到限制值的次数 
memory.memsw.failcnt 显示当前内存(进程内存+页面内存)+交换区达到限制值的次数 
memory.max_usage_in_bytes 显示记录的内存(进程内存+页面内存)使用量的最大值 
memory.memsw.max_usage_in_bytes 显示记录的内存(进程内存+页面内存)+交换区使用量的最大值 
memory.stat 输出统计信息 
memory.force_empty 强制释放分配给分组的内存 
memory.use_hierarchy  设置、显示层次结构的使用 
memory.swappiness  设置、显示针对分组的swappiness(相当于sysctl的vm.swappiness)

二、cgroup使用

1. 需要区分cgroup的公共配置文件和特有配置文件(基于kernel-5.10)

cgroup1_base_files["tasks"].write 回调 group-v1.c 
    cgroup1_tasks_write 
cgroup1_base_files["cgroup.procs"].write 回调 
    cgroup1_procs_write 
        __cgroup1_procs_write 
            trace_android_vh_cgroup_set_task //允许在此加HOOK

比如cpuset特有文件使用的文件在 legacy_files[] 中表示,没有"tasks"、"cgroup.procs"文件。也就是说这个HOOK是所有cgroup共用的,目前已经存在的cgroup有freezer、memory、cpuset、cpu、blkiofreezer、memory、cpuset、cpu、blkio ...,也就说每次前后台切换此HOOK会被调用多次!

参考:
Linux Cgroups详解(三): https://www.cnblogs.com/lisperl/archive/2012/04/23/2466151.html?utm_medium=referral
003_Linux的Cgroup<实例详解>: https://www.cnblogs.com/itcomputer/p/4634942.html

TODO:
Linux Cgroups详解(一):https://www.cnblogs.com/lisperl/archive/2012/04/17/2453838.html
Linux Cgroups详解(二):https://www.cnblogs.com/lisperl/archive/2012/04/18/2455027.html
LXC(Linux containers)快速入门:https://www.cnblogs.com/lisperl/archive/2012/04/15/2450183.html
Linux Cgroup 入门教程:cpuset:https://zhuanlan.zhihu.com/p/121588317


本文参考链接:https://www.cnblogs.com/hellokitty2/p/13775811.html