Linux Note – cgroup

cgroups(control groups)是Linux内核2.6.24引入的一个新特性 ,用来限制、分离和报告一个进程组的资源(CPU、内存、磁盘输入输出等)。常用的ulimit只能基于用户或者用户组来进行资源限制,不能够针对某一进程作出详细限制,缺乏灵活度。
cgroups的一个设计目标是为不同的应用情况提供资源限制的统一接口:
内存资源限制:可以对于一个组设置内存上限;
CPU和I/O的优先级:可以使一些组得到更高的CPU或磁盘I/O使用权;
报告:可以用来衡量系统确实把多少资源用到合适的目标;
分离:分离组的命名空间,这样一个组内不会看到另一个组的进程、网络连接和文件。
控制:冻结组或检查点和重启动

1. 安装cgroup

安装libcgroup.x86_64(Tools and libraries to control and monitor control groups)

开机自动启动cgconfig服务:

该服务使用/etc/cgconfig.conf作为配置文件,该文件文档

虽然以lib开头,libcgroup中也带着所有cgroup管理和控制的可执行文件。

2. 子系统、层级和控制组

(1). cgroup使用各个子系统来管理系统的不同类型的资源,子系统也称为资源控制器。
使用lssubsys -am可以列出所有子系统(无论是否被挂载)。
SHELL# lssubsys -am

cgroup下面有如下subsys, 限制对应的资源:
blkio 这个子系统设置限制每个块设备的输入输出控制。例如:磁盘,光盘以及usb等等。
cpu 这个子系统使用调度程序为cgroup任务提供cpu的访问。
cpuacct 产生cgroup任务的cpu资源报告。
cpuset 如果是多核心的cpu,这个子系统会为cgroup任务分配单独的cpu和内存。
devices 允许或拒绝cgroup任务对设备的访问。
freezer 暂停和恢复cgroup任务。
memory 设置每个cgroup的内存限制以及产生内存资源报告。
net_cls 标记数据包( 这个子系统使用等级识别符(classid)标记网络数据包,可允许 Linux 流量控制程序(tc)
识别从具体 cgroup 中生成的数据包。)。
ns 名称空间子系统。可以把一个数值写到对应的子系统目录的对应文件中。
(2). Control Group以目录层级(hierarchies)的方式来组织,每一个子系统在同一时间只能在一个目录层级下面。默认情况下,每个子系统在/cgroup目录下都有自己的目录层级。
子系统也可以手动挂载到某个目录层级下面,例如创建一个cpu_and_mem目录,该层级下同时使用cpu和mem两个子系统:

#也可以使用-o remount来添加/删除子系统:

这时查看/proc/cgroups信息,可以看到cpu和blkio这两个子系统已经mount到hierarchy中。

我们可以在这个目录结构下,看到所有blkio和cpu子系统的限制参数。

这些参数都可以直接查看,例如:

同理,这些值也可以使用直接修改:

(3). 由于mount了/cgroup/cpu_and_mem这个目录层级,我们使用cgcreate在层级下创建control group,cgcreate的命令语法如下:
cgcreate [-t uid:gid] [-a uid:gid] -g subsystem[,subsystem […]]:/path_to_hierarchy [-g subsystem:/path_to_hierarchy […]]
例如:
cgcreate -g cpu:/webcpu
cpu和blkio之前我们将其mount到了同一hierarchy下面,所以在这里面只有一个子目录生成,其中也有cpu和blkio子系统的全部参数。这些参数继承了父级hierarchy(/cgroup/cpu_and_mem)的值。
也就是说无论webcpu这个control group有没有用到blkio这个组,这个目录层级下面也包含blkio和cpu的全部值。

可以使用cgdelete来删除一个/多个子系统层级下的cg(control group):(比如cgdelete cpu,blkio:webcpu)

但是由于blkio和cpu挂载到同一hierarchy下面,删除blkio:webcpu这个control group会删除webcpu这个目录层级,连带着cpu:webcpu的部分也被删除了。
(4). 下面我们做另外一个测试:
新挂载一个cpuacct子系统

这说明当cg用到的子系统不在同一目录层级下面时候,cgdelete cpuacct:webapp仅仅是删除了cpuacct的层级。
(5). 使用mkdir、rmdir来创建cg

这说明在cgroup的子系统层级或子层级下面创建目录,相当于执行了cgroup命令。该层级下自动继承了父层级下所有的值。
同理,删除

3. cgroup.conf

cgconfig服务可以让cg的定义永久生效,这样重启之后cg依然可用。cgconfig服务的配置文件是/etc/cgconfig.conf。我们可以看到,配置文件里已经默认定义了子系统的mount配置:
mount {
cpuset = /cgroup/cpuset;
cpu = /cgroup/cpu;
cpuacct = /cgroup/cpuacct;
memory = /cgroup/memory;
devices = /cgroup/devices;
freezer = /cgroup/freezer;
net_cls = /cgroup/net_cls;
blkio = /cgroup/blkio;
}
mount的层级也可以根据需要来修改。下面我们直接定义一个组:
group {
[permissions]
{

=

=

}

}
例如:
group example {
cpu {
cpu.shares=100; #根据和其他cpu.shares是比例的关系
}
blkio {
blkio.throttle.read_bps_device = “252:0 1048576″;
}
}
定义好组以后,在对应的下面就会出现: /cgroup/cpu/exmaple 和/cgroup/cpu/exmaple,而相关参数的值也定义到该层级下的对应参数中。
关于permission项,root用户当然拥有该cg的全部权限,其他用户遵循下面的语法定义:
perm {
​ ​task {
​ ​ ​uid = ;
​ ​ ​gid = ;
​ ​}
​ ​admin {
​ ​uid = ;
​ ​gid = ;
​}
}
其中,task用户和组是cg文件的属主。该用户/组可以修改cg下面的tasks文件的属主(见第4节)。那么task用户/组就可以使用使用这个cg来管理某个进程。
admin用户和组拥有该cg层级下全部文件的权限,也就是说admin用户可以修改参数值、创建子cg等。
修改完cgconfig.conf后,需要重启cgconfig服务,注意重启该服务时pwd不能为/cgroup层级下。
SHELL# service cgroup restart

4. 使用cg管理进程

(1). 进程的cgroup
进程之前也存在层级和继承的关系。当一个进程被fork出来时,它会继承父进程的大部分属性和内存资源。其中所属的cgroup也是被继承过来的。我们可以在下面的地方找到某个进程所属的cgroup:

这样我们就得到了1号进程(init)的cg信息,它位于所有子系统的根层级。

(2). 手动管理进程
有三种方法可以使用cg来管理某一个进程,当进程已经存在时,可以直接将其输出到cg层级的tasks文件中来(可以用该层级task user/group来进行)。

或者使用cgclassify命令:

也可以使用cgexec来指定一个新执行的进程到cg中:

(3). cgred
上面的方法都缺乏灵活性,cgroup提供了一个专门的服务——cgred来将进程指定到某个cg中来。该服务也有一个对应的服务:/etc/cgrules.conf,定义格式如下:
user|@group:[program] controller cgroup
例如 把所有运行dd的进程和oracle.expdp放到blkio/bigload这个cg中,并所有apache用户下的进程指定到cpu和memory的webapp这个cg
*:dd blkio /bigload/ ​ ​ ​ ​ ​ ​ ​#一定要以/结尾
oracle:expdp blkio /bigload/
apache.* cpu,meory /example/
然后reload服务,就可以生效。

5. 一些常用的子系统参数

(1). 内存大小
memory.limit_in_bytes和memory.limit_sw_in_bytes是最常用的限制内存大小的参数,limit_in_bytes限制了内存总量的使用,而limit_sw_in_bytes限制了交换空间和物理的内存的使用。当二者想当时,相当于禁用了交换空间。
(2). 磁盘I/O
限制读吞吐量:
blkio.throttle.read_bps_device MAJOR_DEVICE#:MINOR_DEVICE#
blkio.throttle.read_iops_device MAJOR_DEVICE#:MINOR_DEVICE#
限制写吞吐量:
blkio.throttle.write_bps_device MAJOR_DEVICE#:MINOR_DEVICE#
blkio.throttle.write_iops_device MAJOR_DEVICE#:MINOR_DEVICE#
(3). cpu.shares
包含用来指定在 cgroup 中的任务可用的相对共享 CPU 时间的整数值。例如:在两个 cgroup 中都将 cpu.shares 设定为 1 的任务将有相同的 CPU 时间,但在 cgroup 中将 cpu.shares 设定为2 的任务可使用的 CPU 时间是在 cgroup 中将 cpu.shares 设定为 1 的任务可使用的 CPU 时间的两倍。
其他的参数的详细解释可以在RHEL6 Resouce Management文档中找到。

^^

参考

wikimedia
RHEL docs
Linux Manual

Posted in Linux.