cgroups
cgroups
介绍
CGroup 是 Control Groups 的缩写,是 Linux 内核提供的一种可以限制、记录、隔离进程组 (process groups) 所使用的物力资源 (如 cpu memory i/o 等等) 的机制。
CGroup 相关概念解释
任务(task)。在 cgroups 中,任务就是系统的一个进程;
控制族群(control group)。控制族群就是一组按照某种标准划分的进程。Cgroups 中的资源控制都是以控制族群为单位实现。一个进程可以加入到某个控制族群,也从一个进程组迁移到另一个控制族群。一个进程组的进程可以使用 cgroups 以控制族群为单位分配的资源,同时受到 cgroups 以控制族群为单位设定的限制;
层级(hierarchy)。控制族群可以组织成 hierarchical 的形式,既一颗控制族群树。控制族群树上的子节点控制族群是父节点控制族群的孩子,继承父控制族群的特定的属性;
子系统(subsystem)。一个子系统就是一个资源控制器,比如 cpu 子系统就是控制 cpu 时间分配的一个控制器。子系统必须附加(attach)到一个层级上才能起作用,一个子系统附加到某个层级以后,这个层级上的所有控制族群都受到这个子系统的控制。
相互关系:
每次在系统中创建新层级时,该系统中的所有任务都是那个层级的默认 cgroup(我们称之为 root cgroup,此 cgroup 在创建层级时自动创建,后面在该层级中创建的 cgroup 都是此 cgroup 的后代)的初始成员;
一个子系统最多只能附加到一个层级;
一个层级可以附加多个子系统;
一个任务可以是多个 cgroup 的成员,但是这些 cgroup 必须在不同的层级;
系统中的进程(任务)创建子进程(任务)时,该子任务自动成为其父进程所在 cgroup 的成员。然后可根据需要将该子任务移动到不同的 cgroup 中,但开始时它总是继承其父任务的 cgroup。
例如CGroup 层级关系显示,CPU 和 Memory 两个子系统有自己独立的层级系统,而又通过 Task Group 取得关联关系:
CGroup 技术可以被用来在操作系统底层限制物理资源,起到 Container 的作用。图中每一个 JVM 进程对应一个 Container Cgroup 层级,通过 CGroup 提供的各类子系统,可以对每一个 JVM 进程对应的线程级别进行物理限制,这些限制包括 CPU、内存等等许多种类的资源。例如:
CGroup的子系统包括:
- blkio 设置限制每个块设备的输入输出控制。例如:磁盘,光盘以及usb等等。
- cpu 使用调度程序为cgroup任务提供cpu的访问。
- cpuacct 产生cgroup任务的cpu资源报告。
- cpuset 如果是多核心的cpu,这个子系统会为cgroup任务分配单独的cpu和内存。
- devices 允许或拒绝cgroup任务对设备的访问。
- freezer 暂停和恢复cgroup任务。
- memory 设置每个cgroup的内存限制以及产生内存资源报告。
- net_cls 标记每个网络包以供cgroup方便使用。
- net_prio — 这个子系统用来设计网络流量的优先级
- hugetlb — 这个子系统主要针对于HugeTLB系统进行限制,这是一个大页文件系统。
- perf_event 增加了对每group的监测跟踪的能力,即可以监测属于某个特定的group的所有线程以及运行在特定CPU上的线程,此功能对于监测整个group非常有用
- systemd
使用
在实际的使用过程中,你需要通过挂载(mount)cgroup文件系统新建一个层级结构,挂载时指定要绑定的子系统,缺省情况下默认绑定系统所有子系统。把cgroup文件系统挂载(mount)上以后,你就可以像操作文件一样对cgroups的hierarchy层级进行浏览和操作管理(包括权限管理、子文件管理等等)。除了cgroup文件系统以外,内核没有为cgroups的访问和操作添加任何系统调用。
层级激活后,/proc目录下的每个task PID文件夹下都会新添加一个名为cgroup的文件,列出task所在的层级,对其进行控制的子系统及对应cgroup文件系统的路径。
一个cgroup创建完成,不管绑定了何种子系统,其目录下都会生成以下几个文件,用来描述cgroup的相应信息。同样,把相应信息写入这些配置文件就可以生效,内容如下。
- tasks:这个文件中罗列了所有在该cgroup中task的PID。该文件并不保证task的PID有序,把一个task的PID写到这个文件中就意味着把这个task加入这个cgroup中。
- cgroup.procs:这个文件罗列所有在该cgroup中的线程组ID。该文件并不保证线程组ID有序和无重复。写一个线程组ID到这个文件就意味着把这个组中所有的线程加到这个cgroup中。
- notify_on_release:填0或1,表示是否在cgroup中最后一个task退出时通知运行release agent,默认情况下是0,表示不运行。
- release_agent:指定release agent执行脚本的文件路径(该文件在最顶层cgroup目录中存在),在这个脚本通常用于自动化umount无用的cgroup。
除了上述几个通用的文件以外,绑定特定子系统的目录下也会有其他的文件进行子系统的参数配置。
在创建的hierarchy中创建文件夹,就类似于fork中一个后代cgroup,后代cgroup中默认继承原有cgroup中的配置属性,但是你可以根据需求对配置参数进行调整。这样就把一个大的cgroup系统分割成一个个嵌套的、可动态变化的“软分区”。
http://www.infoq.com/cn/articles/docker-kernel-knowledge-cgroups-resource-isolation/
subsystem配置参数用法
源代码
源代码在src/linux目录下,对linux相关的一些功能进行了包装。
cgroups
src/linux/cgroups.cpp
函数名称 | 功能 | 参数 |
---|---|---|
mount | mount cgroups虚拟文件系统到指定目录 | |
umount | umount cgroups虚拟文件系统指定的层次目录 | |
cloneCpusetCpusMems | 从父组中拷贝'cpuset.cpus' and 'cpuset.mems' 到子组 | |
create | 在给定的cgroups层次创建cgroup | |
move | ||
read | ||
write | ||
prepare | ||
verify | ||
enable | ||
hierarchies | 返回cgroups的整个目录层次 | |
hierarchy | 返回cgroups的某个子系统的目录层次 | |
enabled | subsystems | |
busy | ||
subsystems | ||
subsystems | hierarchy | |
mount | hierarchy subsystems retry |
|
unmount | hierarchy | |
mounted | hierarchy subsystems |
|
create |
.....
代码都很直观,分析一个prepare作为例子:
prepare
参数:
- const string& baseHierarchy,
- const string& subsystem,
- const string& cgroup
流程:
- 415-423:内核是否已经支持cgroups?是否根用户权限运行?
- 428-433:检查子系统是否已经安装到指定的层次目录上
- 435-460:若没有,执行mount
- 465-482:创建cgroup
- .......