Linux CGroup全称Linux Control Group, 是Linux内核的一个功能,用来限制,控制与分离一个进程组群的资源(如CPU、内存、磁盘输入输出等)。这个项目最早是由Google的工程师在2006年发起(主要是Paul Menage和Rohit Seth),最早的名称为进程容器(process containers)。在2007年时,因为在Linux内核中,容器(container)这个名词太过广泛,为避免混乱,被重命名为cgroup,并且被合并到2.6.24版的内核中去。
Linux CGroupCgroup 可让您为系统中所运行任务(进程)的用户定义组群分配资源 — 比如 CPU 时间、系统内存、网络带宽或者这些资源的组合。您可以监控您配置的 cgroup,拒绝 cgroup 访问某些资源,甚至在运行的系统中动态配置您的 cgroup。
主要提供了如下功能:
- Resource limitation: 限制资源使用,比如内存使用上限以及文件系统的缓存限制。
- Prioritization: 优先级控制,比如:CPU利用和磁盘IO吞吐。
- Accounting: 一些审计或一些统计,主要目的是为了计费。
- Control: 挂起进程,恢复执行进程。
使用 cgroup,系统管理员可更具体地控制对系统资源的分配、优先顺序、拒绝、管理和监控。可更好地根据任务和用户分配硬件资源,提高总体效率。
在实践中,系统管理员一般会利用CGroup做下面这些事(有点像为某个虚拟机分配资源似的):
- 隔离一个进程集合(比如:nginx的所有进程),并限制他们所消费的资源,比如绑定CPU的核。
- 为这组进程 分配其足够使用的内存
- 为这组进程分配相应的网络带宽和磁盘存储限制
- 限制访问某些设备(通过设置设备的白名单)
概念、术语
- 任务(Tasks):就是系统的一个进程。
- 控制组(Control Group):一组按照某种标准划分的进程,比如官方文档中的Professor和Student,或是WWW和System之类的,其表示了某进程组。Cgroups中的资源控制都是以控制组为单位实现。一个进程可以加入到某个控制组。而资源的限制是定义在这个组上。从cgroup文件系统看,cgroup的呈现就是一个目录带一系列的可配置文件。
- 层级(Hierarchy):控制组可以组织成hierarchical的形式,既一颗控制组的树(目录结构)。控制组树上的子节点继承父结点的属性。简单点说,hierarchy就是在一个或多个子系统上的cgroups目录树。
- 子系统(Subsystem):一个子系统就是一个资源控制器,比如CPU子系统就是控制CPU时间分配的一个控制器。子系统必须附加到一个层级上才能起作用,一个子系统附加到某个层级以后,这个层级上的所有控制族群都受到这个子系统的控制。Cgroup的子系统可以有很多,也在不断增加中。
Subsystem介绍
subsystem 是一组资源控制的模块。包含以下几项。
- blkio 设置对块设备输入输出的访问控制。例如磁盘
- cpu 设置cgroup中进程的cpu被调度策略。
- cpuacct 可以统计cgroup中进程的cpu占用。
- cpuset 在多核机器上,设置cgroup中进程可以使用的cpu和内存。此处仅限于NUMA架构。
- devices 控制cgroup对设备的访问。
- freezer 挂起(suspend)和恢复(resue) cgroup中的进程。
- memory 用于控制cgroup中进程的内存占用。
- net_cls 将cgroup中进程产生的网络包分类,便于linux tc(traffic controller)可以根据分类区分出来自某个cgroup包并做监控。
- net_prio 设置cgroup中进程产生的网络流量的优先级。
- ns 使cgroup中的进程在新的Namespace中fork新进程时,创建一个新的cgroup,这个cgroup包含新的Namespace中的进程。
Hierarchy与cgroup介绍
Hierarchy是一棵树,每个节点都是一个cgroup,cgroup中是属于该控制组的进程,一个Hierarchy中包含系统中所有的进程,一开始挂载生成一个Hierarchy树时,Hierarchy中只有一个根节点,也就是只有一个root cgroup,系统中所有的进程都在这个cgroup中,随后,可以根据需求,创建新的cgroup,并可以按需求将进程加入到相应的cgroup中。新的cgroup在Hierarchy表现为一个节点,当一个进程迁移到一个cgroup时,就自动脱离了之前的cgroup,也就是在一个Hierarchy中,一个进程只会在一个cgroup节点中。进行进程的cgroup迁移时,需要满足的条件是,对目标cgroup有写入权限,执行者为root或目标进程的拥有者。但进程fork子进程时,子进程将会加入到fork时父进程所在的cgroup中,当对父进程进行了cgroup的迁移时,不会影响到之前已经存在的子进程的cgroup归属。
1 | Hierarchy决定了进程归属于哪一个cgroup,而subsystem确定进行什么限制,当两者关联在一起,就决定了对哪些进程进行哪些限制。 |
CGroup的使用
cgroups 是通过 VFS 把功能暴露给用户态的。
1 | VFS 是一个内核抽象层,能够隐藏具体文件系统的实现细节,从而给用户态进程提供一套统一的 API 接口。VFS 使用了一种通用文件系统的设计,具体的文件系统只要实现了 VFS 的设计接口,就能够注册到 VFS 中,从而使内核可以读写这种文件系统。 |
用户可以通过对cgroup文件系统进行操作来实现与cgroup的交互。
cgroup文件系统挂载到目录后,呈现出的样子是,一棵Hierarchy树就是一棵目录树,每一个目录都是一个节点,对应一个cgroup,目录的名字就是cgroup的名字,每个cgroup目录下,会有一些文件,这些文件包括对该cgroup中进程的记录等、与该cgroup相关联的subsystem的配置信息等、子cgroup的目录。当挂载目录并与指定的subsytem相关联的时候,root cgroup目录下就会默认生成cgroup相关的记录文件,和subsystem相关的配置文件。当在cgroup目录下,建立子目录时,就创建了子cgroup,子目录中将会自动生成cgroup相关的记录文件,和与父cgroup所关联的subsystem相关的配置文件。理解了各个文件的含义,就可以通过对这些文件进行读写操作,完成与cgroup的交互。
对cgroup文件系统的操作,通常可以是一下几种形式:
用户可以通过将cgroup文件系统挂载到系统中某个目录下,然后对该目录进行文件操作来实现与cgroup的交互。
1
2
3
4
5
6
7
8挂载cgroup文件系统:
mount -t cgroup -o subsystems name /cgroup/name
其中 subsystems 表示需要挂载的 cgroups 子系统, /cgroup/name 表示挂载点,这条命令同时在内核中创建了一个cgroups 层级结构。
挂载一棵cgroup树,但不关联任何subsystem:
mount -t cgroup -o none,name=xxxxx xxxxx /path_to_cgroup1
2显示cgroup subsystem的挂载情况
lssubsys -m1
2
3
4
5创建子cgroup,在父cgroup目录下创建子目录即可
mkdir
移除cgroup,删除对应的目录
rmdir1
2
3
4将进程888添加到指定进程组
echo 888 > path_to_cgroup/cgroup.procs
非root账号:
sudo sh -c 'echo 888 > path_to_cgroup/cgroup.procs'在rh_6系列中,可以通过libcgroup工具来进行交互,安装该工具后, 启动cgconfig服务,将会自动进行cgroup文件系统的挂载,根据/etc/cgconfig.conf中的配置,将决定其挂载位置,以及挂载后创建相关的cgroup和相关的subsystem限制。通常默认的挂载位置为/cgroup/。同时libcgroup工具提供了一些命令,可以方便地进行进程的cgroup迁移,cgroup创建和销毁,进程创建并加入指定的cgroup等操作。
1
2
3
4
5
6
7
8
9
10
11启动cgconfig服务
service cgconfig start
设置 cgroups 子系统的参数
cgset -r parameter=value path_to_cgroup
在某一个 cgroups 下启动进程
gexec -g subsystems:path_to_cgroup command arguments
创建cgroup
cgcreate在rh_7系统中,使用systemd对cgroup文件系统进行维护,systemd将在/sys/fs/cgroup/挂载cgroup文件系统。可以通过systemd提供的相关命令进行相关的资源监控和限制。
1
systemctl set-property XXX.service XXXXXXX=XX
由于一个subsystem只能附加到一个hierarchy上面。所以,如果系统中已经将一个subsystem附加到了一个Hierarchy上,当再次挂载与该subsystem相关联的Hierarchy时,将会失败。所以,倘若在一个系统中使用多种方式进行操作,将有相互干扰的风险,需要尤其注意。
Tips
1 | 1. 系统创建hierarchy 之后,所有的进程都会加入这个hierarchy的cgroup的根节点。在这个cgroup根节点是hierarchy默认创建的。 |
参考: