RHEL6 使用控制组

在RHEL6系统中,管理cgroup的方法是使用libcgroup软件包中的相关命令工具。这样就可以mount层次结构并且使用shell命令和工具来设置cgroup参数(非持久化):

yum install libcgroup

cgconfig服务

libcgroup软件包提供安装了cgconfig服务,提供了便捷的方式来创建层次结构,添加子系统到层次结构,以及管理层次结构中的cgroups。建议使用cgconfig来管理系统中的层次结构和cgroups。

注意:Red Hat Enterprise Linux 6默认没有启动cgconfig服务。当启动cgconfig服务,这个服务将读取/etc/cgconfig.conf这个cgroup配置文件。此时cgroups将依次重新创建并保持持久化。根据配置文件内容的不同,cgconfig可以创建层次结构(hierarchies),挂载必要的文件系统,创建cgroups,并设置每个组的子系统参数。

默认的/etc/cgconfig.conf文件是在libcgroup软件包安装创建的并为每个子系统挂载了一个独立hierarchy,并将subsystem添加到hierarchy。cgconfig服务也允许在/etc/cgconfig.d/目录下创建配置文件,并从/etc/cgconfig.conf中加载这些配置文件。

启动cgconfig服务

service cgconfig start

启动后检查层次结构挂载

lssubsys -m

显示输出

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

此时,使用ls命令可以看到挂载的文件系统中的内容,如 ls /cgroup/blkio可以看到

blkio.io_merged         blkio.throttle.io_service_bytes   blkio.weight_device
blkio.io_queued         blkio.throttle.io_serviced        cgroup.event_control
blkio.io_service_bytes  blkio.throttle.read_bps_device    cgroup.procs
blkio.io_serviced       blkio.throttle.read_iops_device   notify_on_release
blkio.io_service_time   blkio.throttle.write_bps_device   release_agent
blkio.io_wait_time      blkio.throttle.write_iops_device  tasks
blkio.reset_stats       blkio.time
blkio.sectors           blkio.weight

当停止cgconfig服务(service cgconfig stop),则会卸载所有其挂载的层次结构:

service cgconfig stop

此时再使用lssubsys -m命令,将看不到任何输出。同时,在/cgroup/blkio等层次结构挂载卸载后,目录下都为空。

/etc/cgconfig.conf配置文件

/etc/cgconfig.conf配置文件包含两种主要的内容 - mountgroup。其中,mount内容创建和挂载层次结构作为虚拟文件系统,并添加子系统到层次结构。mount对象定义使用以下语法:

mount {
    subsystem = /cgroup/hierarchy;
    ...
}

默认的配置类似如下

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;
}

上述配置的subsystem自动挂载到/cgroup/目录下的对应层次结构(hierarchies)。建议使用这些默认的层次结构来设置控制组。注意,多个子系统可以挂载到单一的层次结构,但是每个子系统只能挂载一次。

  • 创建mount节点案例

以下案例创建cpuset子系统的hirearchy

mount {
    cpuset = /cgroup/red;
}

对应的shell命令如下:

mkdir /cgroup/red
mount -t cgroup -o cpuset red /cgroup/red

由于每个子系统只能挂载一次,所以如果cpuset已经存在,则上述挂载会失败。

  • 创建group对象

group会创建cgroups并设置subsystem参数,使用以下语法:

group <name> {
    [<permissions>]
    <controller> {
        <param name> = <param value>;
    }
}

以下案例创建一个SQL服务的cgroup,设置在sqladmin组中的用户权限来添加任务到cgroup,以及root用户修改subsystem参数:

group daemons {
    cpuset {
        cpuset.mems = 0;
        cpuset.cpus = 0;
    }
}
group daemons/sql {
    perm {
        task {
            uid = root;
            gid = sqladmin;
        } admin {
            uid = root;
            gid = root;
        }
    }
    cpuset {
        cpuset.mems = 0;
        cpuset.cpus = 0;
    }
}

上述配置对等的shell命令如下:

mkdir -p /cgroup/red/daemons/sql
chown root:root /cgroup/red/daemons/sql/*
chown root:sqladmin /cgroup/red/daemons/sql/tasks
echo $(cgget -n -v -r cpuset.mems /) > /cgroup/red/daemons/cpuset.mems
echo $(cgget -n -v -r cpuset.cpus /) > /cgroup/red/daemons/cpuset.cpus
echo 0 > /cgroup/red/daemons/sql/cpuset.mems
echo 0 > /cgroup/red/daemons/sql/cpuset.cpus

重启cgconfig服务使得更改生效。

注意:当修改完 /etc/cgconfig.conf 配置文件后,需要重启cgconfig服务才能够生效。然而,重启这个服务会导致整个cgroup hierarchy重建,意味着删除所有现有的cgroups(例如,所有被libvirtd使用的cgroups)。重启cgconfig服务命令如下:

service cgconfig restart

/etc/cgconfig.d/目录

/etc/cgconfig.d/目录保留用于存储特殊的应用程序和使用情况的配置文件。这些文件使用.conf后缀名,并且使用和/etc/cgconfig.conf相同的语法。

cgconfig服务会首先处理/etc/cgconfig.conf配置文件,然后继续处理/etc/cgconfig.d/目录下的配置文件。需要注意的是,该目录下文件处理的顺序是不确定的,所以不要在不同的配置文件中定义相同的group。

创建一个Hierarchy和添加Subsystems

对于运行系统:

创建新的hierarchy并添加subsystems,如果系统之前没有配置过cgroups,则指令不会立即生效。更改cgroup的tasks参数,则可能会立即作用于tasks。

在一个已经配置了cgroups的系统(手工或者通过cgconfig服务),这些命令会失败,除非你首先umount现存的hierarchies。不要直接在生产系统上测试这些指令

下面案例创建cpu_and_mem的层次结构,并添加cpu,cpuset,cpuacct,memory的subsystems

mount {
    cpuset = /cgroup/cpu_and_mem;
    cpu = /cgroup/cpu_and_mem;
    cpuacct = /cgroup/cpu_and_mem;
    memory = /cgroup/cpu_and_mem;
}

上述配置等同命令:

mkdir /cgroup/cpu_and_mem
mount -t cgroup -o cpu,cpuset,memory cpu_and_mem /cgroup/cpu_and_mem

然后使用命令lssubsys检查

lssubsys -am

可以看到,在执行上述配置命令之前lssubsys -am输出内容

cpuset
ns
cpu
cpuacct
memory
devices
freezer
net_cls
blkio
perf_event
net_prio

执行之后,可以看到系统已经挂载了cpu,cpuset,memory

ns
cpuacct
devices
freezer
net_cls
blkio
perf_event
net_prio
cpuset,cpu,memory /cgroup/cpu_and_mem

上述shell命令执行时,cgconfig并没有启动,是手工挂载的。此时需要卸载cgroup挂载之后才能启动cgconfig服务,否则会冲突。

重新挂载cpu_and_mem层次结构,可以使用remount选项:

mount -t cgroup -o remount,cpu,cpuset,cpuacct,memory cpu_and_mem /cgroup/cpu_and_mem

卸载hierarchy

umount /cgroup/cpu_and_mem

要移除一个层次结构,需要确保在umount层次结构之前,已经移除了所有的子cgroups,或者使用cgclear命令来deactive一个非空的层次结构。

创建Control Groups

使用cgcreate命令来创建cgroups,语法如下:

cgcreate -t uid:gid -a uid:gid -g subsystems:path
  • -t - 指定这个cgroup中拥有tasks伪文件的属主uid和gid

  • -a - 指定这个cgroup中拥有所有伪文件的属主uid和gid,也就是可以修改这个cgroup中任务

  • -g - 指定cgroup创建在哪个hierarchy中,可以对多个hierarchy操作(多个hierarchy之间使用逗号分隔)

cgcreate命令举例:

cgcreate -g cpu,net_cls:/test-subgroup

上述命令创建了2test-subgroup,分别位于cpu_and_memnet这两个hierarchy。

删除Control Groups

cgdelete subsystems:path

举例:

cgdelete cpu,net_cls:/test-subgroup

可以使用参数-r表示删除所有subgroup

当删除cgroup时,所有这个组的任务会移动到它的上级组。

设置参数

通过cgset命令设置一个额用户帐号允许修改相应的cgroup。例如,如果cpuset被挂载在/cgroup/cpu_and_mem/,并且有一个/cgroup/cpu_and_mem/group1子目录,设置CPU访问方法:

cgset -r cpuset.cpus=0-1 group1

这里cgset的语法:

cgset -r parameter=value path_to_cgroup

这里:

  • parameter是对应在指定cgroup目录下的文件

  • value是参数值

  • path_to_cgroup是cgroup层次结构的根相关的路径。例如,设置root组的参数(这里的例子是挂载在/cgroup/cpu_and_mem/目录下的cpuacct子系统),修改/cgroup/cpu_and_mem/目录

cgset -r cpuacct.usage=0 /

当然,由于.就是表示根组,也可以将上述命令修改成

cgset -r cpuacct.usage=0 .

不过,建议使用/

只有少量的参数可以设置到根组。这是因为根组拥有所有的资源。

要设置group1,这个根组的子组:

cgset -r cpuacct.usage=0 group1

可以通过cgset命令复制一个cgroup的参数到另外一个cgroup

cgset --copy-from group1/ group2/

上述设置命令的另外一种方式是直接使用echo命令:

echo 0-1 > /cgroup/cpu_ane_mem/group1/cpuset.cpus

举例:假设要设置控制组agent内存限制8G

cgset -r memory.limit_in_bytes=8589934592 agent

对应配置类似如下

group agent {
       ...
       memory {
               memory.limit_in_bytes = 8192M;
       }
}

将一个进程移动到控制组

要将一个进程移入到一个cgroup,使用cgclassify命令。例如:

cgclassify -g cpu,memory:group1 1701

这个cgclassify语法是:

cgclassify -g subsystems:path_to_cgroup pidlist
  • subsystem是逗号分隔的,或者用*来加载进程到hierarchy相应的所有可用的subsystems。注意如果cgroup在多个层次结构中同名,则-g参数将移动进程到所有组。

  • path_to_cgroup是这个层次结构的cgroup路径

  • pidlist是空格分隔的进程id(PIDs)

如果没有指定-g参数,则cgclassify自动搜索/etc/cgrules.conf,并使用第一个合适的配置行。针对匹配行,cgclassify检查hierarchies和cgroups并移动进程到符合的控制组。

可以添加 --sticky 选项在pid之前,这样所有的子进程将位于相同的cgroup。如果没有设置这个选项,并且cgred服务也在运行,则子进程将基于/etc/cgrules.conf配置中符合的cgruops。然而,其父进程将保留在首次启动的cgroup中。

使用cgclassify,可以同时移动多个进程。例如:

cgclassify -g cpu,memory:group1 1701 1138

替代的方法:

直接将进程的PID写入到cgroup的tasks文件:

echo 1701 > /cgroup/cpu_and_mem/group1/tasks

cgred服务

cgred服务(将启动cgrulesengd daemon)将根据/etc/cgrules.conf配置将进程移动到相应cgroups的tasks中。在/etc/cgrules.conf配置文件中,有如下两种格式:

user subsystems control_group
user:command subsystems control_group

这里user是用户名,或者是以@开头的组名。

这里需要再补充一些细节

在控制组中启动一个进程

注意:在移动一个进程到使用了子系统的cgroup,这些子系统需要先设置好强制参数(mandatory parameters)。例如,在将一个任务移动到使用了cpuset子系统的cgroup之前,你必须先创建好cpuset.cpuscpuset.mems参数。

要将一个进程在cgroup中启动,需要使用cgexec命令。例如,在gruop1的cgroup中启动firefox浏览器,限制到cpu子系统

cgexec -g cpu:group1 firefox http://www.redhat.com

使用cgexec的语法:

cgexec -g subsystems:path_to_cgroup command arguments
  • subsystem是逗号分隔的子系统列表。如果在多个hierarchies中有相同名字的cgroup,则-g参数将在每个groups中创建进程。

  • path_to_cgroup是在hierarchy中的相关cgroup

替代方法

也可以使用shell命令:当启动一个进程,它将继承父进程的group,所以替代方法是先将shell进程移动到组里面,然后在shell中启动组:

echo $$ > /cgroup/cpu_and_mem/group1/tasks
firefox

更好的方法是:

sh -c "echo \$$ > /cgroup/cpu_and_mem/group1/tasks && firefox"

在控制组中启动一个服务

可以在cgroup中启动一系列服务。要在一个cgroup中启动服务,需要满足以下条件:

  • 使用/etc/sysconfig/servicename文件

  • /etc/init.d/functions中使用daemon()功能来启动服务

要设置一个服务以cgroup启动,编辑 /etc/sysconfig 目录下的 配置

Last updated