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.19kernelcgroupcgroup.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)
参考:
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