Red Hat Enterprise Linux 6 提供了一个新的内核特性: CONTROL GROUPS(Cgroups),它为内核提供的一种可以限制、记录、隔离进程组(process groups)所使用的物理资源(如:cpu,memory,IO等等)的机制。
CONTROL GROUPS包括如下子系统:
blkio -- 这个子系统为块设备设定输入/输出限制,比如物理设备(磁盘,固态硬盘,USB 等等)。
cpu -- 这个子系统使用调度程序提供对 CPU 的 cgroup 任务访问。
cpuacct -- 这个子系统自动生成 cgroup 中任务所使用的 CPU 报告。
cpuset -- 这个子系统为 cgroup 中的任务分配独立 CPU(在多核系统)和内存节点。
devices -- 这个子系统可允许或者拒绝 cgroup 中的任务访问设备。
freezer -- 这个子系统挂起或者恢复 cgroup 中的任务。
memory -- 这个子系统设定 cgroup 中任务使用的内存限制,并自动生成由那些任务使用的内存资源报告。
net_cls -- 这个子系统使用等级识别符(classid)标记网络数据包,可允许 Linux 流量控制程序(tc)识别从具体 cgroup 中生成的数据包。
ns -- 名称空间子系统。
2.1.1 安装
# yum install –y libcgroup
2.1.2 启动/停止
# service cgconfig start
# service cgconfig stop
2.2.1 配置文件 /etc/cgconfig.conf
/etc/cgconfig.conf在安装Cgroup后会自动建立,文件包含2部分功能----mount and group:
# cat /etc/cgconfig.conf
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;
}
它将在服务启动后创建和挂载虚拟文件系统,等价于命令:
# mkdir -p /cgroup/cpuset
# mount -t cgroup -o cpuset cpuset /cgroup/cpuset
…….
Example:
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/cpuset/daemons/sql
# chown root:root -R /cgroup/cpuset/daemons
# chown root:sqladmin /cgroup/cpuset/daemons/sql/tasks
# echo $(cgget -n -v -r cpuset.mems /) > /cgroup/cpuset/daemons/cpuset.mems
# echo $(cgget -n -v -r cpuset.cpus /) > /cgroup/cpuset/daemons/cpuset.cpus
# echo 0 > /cgroup/cpuset/daemons/sql/cpuset.mems
# echo 0 > /cgroup/cpuset/daemons/sql/cpuset.cpus
2.2.2 目录 /etc/cgconfig.d/
配置文件所在的目录。下面的文件名以conf作为后缀,语法参见/etc/cgconfig.conf。
cgconfig服务启动时第一个读取的文件是/etc/cgconfig.conf,然后是该目录下的*.conf文件。文件的解析没有排序。不要在多个文件内定义同一个group。
# lssubsys -am
ns
perf_event
net_prio
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
第一列为支持的子系统名称,后面的表示已经挂载的目录。
也可查看指定的子系统:
# lssubsys -m subsystems
subsystems为指定的子系统名称。
对于已经挂载的子系统,同样可以再次挂载:
# mount -t cgroup -o remount,cpu cpu_and_mem /cgroup/cpu
# umount /cgroup/ cpu
2.5.1 创建 Control Groups
语法:cgcreate -t uid:gid -a uid:gid -g subsystems:path
-t 指定允许向 cgroup 分配任务的用户和组 ID
-a 指定允许管理 cgroup 和更改子系统参数的用户和组 ID
-g subsystems:path group名称及挂载路径
Example:
# cgcreate -g cpu,net_cls:/test-subgroup
创建了cpu及net_cls子系统并挂载到/test-subgroup。
2.5.2 删除 Control Groups
语法:cgdelete subsystems:path
Example:
# cgcreate cpu,net_cls:/test-subgroup
2.5.3 设置 Control Groups参数
语法:cgset -r parameter=value path_to_cgroup
如果cpuset 已经挂载到 /cgroup/cpu_and_mem/ 并且存在目录/cgroup/cpu_and_mem/group1,那么可以:
# cgset -r cpuset.cpus=0-1 group1
也可以:
# echo ‘0-1’ > /cgroup/cpu_and_mem/group1/cpuset.cpus
2.5.4 复制 Control Groups参数
也可以对一个已经存在并设置好的参数进行复制。
语法:cgset --copy-from path_to_source_cgroup path_to_target_cgroup
# cgset --copy-from group1/ group2/
这样croup2的参数将从group1复制而来。
设置好参数后,就可以对进程应用Cgroup。
语法:cgclassify -g subsystems:path_to_cgroup pidlist
# cgclassify -g cpu,memory:group1 1701
ID为1701的进程进程将被应用到cpu及memory子系统中的group1中。也就是说ID为1701的进程将受到cpu及memory子系统中的group1中所设定参数的限制。
也可以:
# echo 1701 > /cgroup/cpu_and_mem/group1/tasks
Cgred 服务会启动一个守护进程 cgrulesengd ,它可根据在 /etc/cgrules.conf 文件中设定的参数将任务移动到 cgroup 中。/etc/cgrules.conf 文件可以使用以下两个格式之一:
User hierarchies control_group
例如:
maria devices staff
用户maria 的进程根据在 staff cgroup 中指定的参数访问设备子系统。
启动/停止方法:service cgred start/stop
/etc/cgrules.conf 文件中的条目可包括以下特殊符号:
@ - 当在 user 使用前缀时,代表是一个组群而不是单独用户。例如:@admins 是 admins 组群中的所有用户。
* - 代表“所有”。例如:subsystem 字段中的 * 代表所有子系统。
% - 代表与以上行中项目相同的项目。例如:
@adminstaff devices /admingroup
@labstaff % %(等价于
@labstaff devices /admingroup)
语法:cgexec -g subsystems:path_to_cgroup command arguments
subsystems 是用逗号分开的子系统列表或者用 * 表示所有可用的子系统。
path_to_cgroup 是该 cgroup 的路径。
command 是要运行的命令。
arguments 是该命令所有参数。
还可以在 command 前面添加 -- sticky 将所有子进程放在同一 cgroup 中。如果没有设定这个选项,且 cgred 守护进程正在运行,则将根据在/etc/cgrules.conf 中的设置将子进程分配到 cgroup 中。而该进程本身仍保留在启动它的 cgroup 中。
Example:
# cgexec -g cpu:group1 firefox
这样firefox的进程将被放到cpu子系统的group1中。
也可以:
# echo $$ > /cgroup/lab1/group1/tasks
这样的话,不但firefox进程会被放到相应的cgroup中;在当前窗口的所有进程均会被放到该cgroup中。如果不希望这样的后果,可以:
# sh -c "echo \$$ > /cgroup/cpu_and_mem/group1/tasks && firefox"
2.8.1 将服务放进cgroup中
要将一个服务放到cgroup中,服务需要具备以下条件:
ⅰ可以使用 /etc/sysconfig/servicename 文件。
ⅱ必须使用 /etc/init.d/functions 的 daemon() 功能启动该服务
然后编辑文件/etc/sysconfig/servicename,添加内容:CGROUP_DAEMON="subsystem:control_group"
Example:
# cat /etc/sysconfig/httpd
CGROUP_DAEMON="cpuset:group1"
# service httpd start
httpd服务将被加到cpuset子系统的group1中。
2.9.1 生成配置文件之cgsnapshot
列出当前配置
# cgsnapshot –s
输出配置文件
# cgsnapshot -f ~/test/cgconfig_test.conf
不要将输出文件直接输出到 /etc/cgconfig.conf,因为 -f 参数将会覆盖任何文件。
也可以为子系统创建配置文件。通过指定一个子系统的名称,则输出将包含于该子系统的相应配置的:
# cgsnapshot cpuacct
设置黑名单
# cgsnapshot -b ~/test/my_blacklist.conf
如果不指定文件,则使用默认文件/etc/cgsnapshot_blacklist.conf。
设置白名单
# cgsnapshot -w ~/test/my_whitelist.conf
没有用默认文件。
另,在使用cgsnapshot –f时,如果既不指定黑名单,也不指定白名单,那么会有相关的警告信息。因此可以使用 -t 参数。
# ps -O cgroup
如果已知进程的PID,则可以:
# cat /proc/PID/cgroup
列出系统中的cgroup
# lscgroup
也可以:
# lscgroup controller:path
Example:
# lscgroup cpuset:daemons
显示具体 cgroup 的参数:
# cgget -r parameter list_of_cgroups
Example:
# cgget -r cpuset.cpus -r memory.limit_in_bytes group1 group2
显示 cgroup lab1 和 lab2 的 cpuset.cpus 和 memory.limit_in_bytes 值。
如果不知道 parameter ,可以:
# cgget -g cpuset /
要清除整个 cgroup 文件系统,请使用 cgclear 命令。
如果有些group没有写在配置文件中那么使用该命令后想要再次恢复,那么只能手动操作。
blkio限额类是主要有两种策略,一种是基于完全公平队列调度(CFQ:Completely Fair Queuing )的按权重分配各个 cgroup 所能占用总体资源的百分比,好处是当资源空闲时可以充分利用,但只能用于最底层节点 cgroup 的配置;另一种则是设定资源使用上限,这种限额在各个层次的 cgroup 都可以配置,但这种限制较为生硬,并且容器之间依然会出现资源的竞争。
blkio 子系统提供2种策略来控制访问 I/O:
权重比例。
I/O 使用上限。
3.1.1. 权重比例
blkio.weight
设定默认使用的权重比例,取值范围:100—1000。此值会被blkio.weight_device值覆盖。
echo 500 > blkio.weight
blkio.weight_device
设定指定设备的使用的权重比例,取值范围:100—1000。此值会覆盖blkio.weight设定值。该值的格式为:major:minor weight,即,主设备号:次设备号 权重。例如:设定硬盘sda的访问权重为500.
# ll /dev/sda
brw-rw---- 1 root disk 8, 0 Aug 15 15:42 /dev/sda
主设备号为8,次设备号为0.
echo 8:0 500 > blkio.weight_device
3.1.2. I/O 使用上限
blkio.throttle.read_bps_device / blkio.throttle.write_bps_device
指定 cgroup 中某设备每秒钟读/写数据的字节上限。其格式为 major:minor bytes_per_second。
blkio.throttle.read_iops_device / blkio.throttle.write_iops_device
指定 cgroup 中某设备每秒钟可以执行的读/写请求数上限。其格式为major:minor operations_per_second。
3.1.3. blkio 统计参数
blkio.reset_stats
向该文件中写入一个整数,可以重置该 cgroup 中的统计计数。
blkio.time
统计 cgroup 对具体设备的 I/O 访问时间。内容有三个字段:major, minor 和time。time 的单位为毫秒(ms); 格式major:minor milliseconds
blkio.sectors
统计 cgroup 对具体设备的扇区读写数。内容有三个字段:major, minor 和sectors(表示磁盘的扇区数)。 格式 major:minor sector_count
blkio.avg_queue_size
统计平均IO队列大小。这个报告只有在将系统设定为 CONFIG_DEBUG_BLK_CGROUP=y 时可用。
blkio.group_wait_time
cgroup 等待每个队列的时间总计(单位为纳秒 -- ns)。每次这个 cgroup 的队列获得一个时间单位时就会更新这个报告,因此如果在 cgroup 等待时间单位时读取这个伪文件,则该报告将不会包含等待当前队列中的操作的时间。请注意这个报告只有在将系统设定为 CONFIG_DEBUG_BLK_CGROUP=y 时可用。
blkio.empty_time
报告 cgroup 在没有任何等待处理请求时花费的时间总计(单位为纳秒 -- ns)。每次这个 cgroup 有等待处理请求时都会更新这个报告,因此如果在 cgroup 没有任何等待处理请求是读取这个伪文件,则该报告中不会包含消耗在当前空状态中的时间。请注意这个报告只有在将该系统设定为 CONFIG_DEBUG_BLK_CGROUP=y 时可用。
blkio.idle_time
报告调度程序在 cgroup 等待比已经在其它队列或者来自其它组群请求更好的请求时显示闲置的时间总计(单位为纳秒 -- ns)。每次该组群不显示闲置时就会更新这个报告,因此如果您在 cgroup 闲置时读取这个伪文件,则该报告将不会包括消耗在当前闲置状态的时间。请注意,只有在将系统设定为 CONFIG_DEBUG_BLK_CGROUP=y时这个报告才可用。
blkio.dequeue
报告 cgroup 的 I/O 操作请求被具体设备从队列中移除的次数。条目有三个字段:major、minor和number。major和minor是在Linux分配的设备中指定的设备类型和节点数,number是将该组群从队列中移除的次数。请注意这个报告只有在将系统设定为CONFIG_DEBUG_BLK_CGROUP=y时可用。
blkio.io_serviced
统计 cgroup 对具体设备的读写操作数。内容有四个字段:major, minor,operation (read, write, sync, or async)和 number(表示操作的次数)。 格式major:minor operation number
blkio.io_service_bytes
统计 cgroup对具体设备的读写字节数。内容有四个字段:major, minor, operation (read, write, sync, or async)和 bytes(表示传输的字节数)。 格式major:minor operation bytes
blkio.io_service_time
统计 cgroup 对指定设备的 I/O 操作发送请求和完成请求之间的时间。条目有四个字段:major, minor, operation 和 time,其中 time 的单位为纳秒(ns)。
blkio.io_wait_time
统计 cgroup 对具体设备的 I/O 操作在队列调度中等待的时间。内容有四个字段:major,minor, operation 和 time,其中 time 的单位为纳秒(ns),这意味着对于ssd硬盘也是有意义的。 格式major:minor operation time
blkio.io_merged
统计 cgroup 将 BIOS 请求合并到 I/O 操作请求的次数。内容有两个字段:number和 operation。 格式number operation
blkio.io_queued
统计I/O 操作排队的请求数。内容有两个字段:number 和 operation(read, write, sync, or async)。 ,格式number operation
blkio.throttle.io_serviced
统计 cgroup 对具体设备的读写操作数。blkio.io_serviced 与blkio.throttle.io_serviced的不同之处在于,CFQ 调度请求队列时,前者不会更新。
内容有四个字段:major, minor,operation (read, write, sync, or async)和 number(表示操作的次数)。 格式major:minor operation operations_per_second
blkio.throttle.io_service_bytes
统计 cgroup对具体设备的读写字节数。blkio.io_service_bytes 与blkio.throttle.io_service_bytes 的不同之处在于,CFQ 调度请求队列时,前者不会更新。内容有四个字段:major, minor, operation (read, write, sync, or async)和 bytes(表示传输的字节数)。 格式major:minor operation bytes_per_second.
blkio.recursive_*:各类型的统计都有一个递归版本,Docker 中使用的都是这个版本。获取的数据与非递归版本是一样的,但是包括 cgroup 所有层级的监控数据。
3.1.4. Example Usage
1. # lssubsys -am |grep blkio
blkio /cgroup/blkio
2. # mkdir /cgroup/blkio/test{1..3}
3. # dd if=/dev/zero of=file_1 bs=1M count=1000
1000+0 records in
1000+0 records out
1048576000 bytes (1.0 GB) copied, 14.017 s, 74.8 MB/s
# dd if=/dev/zero of=file_2 bs=1M count=1000
4 # sync && echo 3 > /proc/sys/vm/drop_caches
5. # cgexec -g blkio:test1 time dd if=file_1 of=/dev/null &
# cgexec -g blkio:test2 time dd if=file_2 of=/dev/null &
6. # iotop –o
Total DISK READ: 42.45 M/s | Total DISK WRITE: 0.00 B/s
TID PRIO USER DISK READ DISK WRITE SWAPIN IO> COMMAND
45224 be/4 root 25.71 M/s 0.00 B/s 0.00 % 99.99 % dd if=file_1 of=/dev/null
45222 be/4 root 16.74 M/s 0.00 B/s 0.00 % 12.12 % dd if=file_2 of=/dev/null
7. # echo 8:0 4096000 > /cgroup/blkio/test3/blkio.throttle.read_bps_device
8. # sync && echo 3 > /proc/sys/vm/drop_caches
9. # cgexec -g blkio:test3 dd if=file_1 of=/dev/null
10. # dd if=file_1 of=/dev/null
步骤1—6设定了test2为test1的读取比例限定,即:test2 的读取速度为test1读取速度的一半。通过iotop的观察,应用于test2的file_2的读取速度接近应用于test1的file_1 的50% 。
步骤7—10中,比较了设定IO读取上限与不设定上限的结果:步骤9的结果为3.1M/s,而步骤10的结果为42 M/s 。
blkio.throttle.* 的限制是针对整个 cgroup 组的,而不是针对组中单个进程的。
3.2. cpu
CPU 资源的控制也有两种策略,一种是完全公平调度 (CFS:Completely Fair Scheduler)策略,提供了限额和按比例分配两种方式进行资源控制;另一种是实时调度(Real-Time Scheduler)策略,针对实时进程按周期分配固定的运行时间。配置时间都以微秒(µs)为单位,文件名中用us表示。
CPU 子系统提供2种调度方法:
Completely Fair Scheduler (CFS) — 按指定比例分配调度CPU 的使用时间。可能会有抢占CPU的情况。
Real-Time scheduler (RT) — 指定绝对时间分配CPU 。
3.2.1. CFS Tunable Parameters
cpu.cfs_period_us
规定CPU的时间周期(单位是微秒)。最大值是1秒,最小值是1000微秒。如果在一个单CPU的系统内,要保证一个cgroup 内的任务在1秒的CPU周期内占用0.2秒的CPU时间,可以通过设置cpu.cfs_quota_us 为200000和cpu.cfs_period_us 为 1000000 。
cpu.cfs_quota_us
在单位时间内(即cpu.cfs_period_us设定值)可用的CPU最大时间(单位是微秒)。cpu.cfs_quota_us值可以大于cpu.cfs_quota_us值,例如在一个双CPU的系统内,想要一个cgroup内的进程充分的利用2个CPU,可以设定cpu.cfs_quota_us为 200000 及cpu.cfs_period_us为 100000 。
当设定cpu.cfs_quota_us为-1时,表明不受限制,同时这也是默认值(除了root cgroup外)。
cpu.stat
CPU 时间的相关统计:
nr_periods —周期间隔数。即,在指定了cfs_period_us后,经历的数量。
nr_throttled — 因超出cpu.cfs_quota_us的限额时间而被终止的次数。
throttled_time — cgroup里的task总共被限制了多少纳秒。
Relative Shares Tunable Parameters
cpu.shares
通过一个整数的数值来调节cgroup所占用的cpu时间。例如,有2个cgroup(假设为CPU1,CPU2),其中一个(CPU1)cpu.shares设定为100另外一个(CPU2)设为200,那么CPU2所使用的cpu时间将是CPU1所使用时间的2倍。cpu.shares 的值必须为2或者高于2 。
注意,在一个四核的CPU系统上,如果cgroup A设定使用CPU的比例为 25% ,cgroup B 为75% 时, 并且1个进程在 cgroup A中,3个进程在cgroup B中,那么CPU的分配可能会像下面这样:
PID |
cgroup |
CPU |
CPU share |
100 |
A |
0 |
100% of CPU0 |
101 |
B |
1 |
100% of CPU1 |
102 |
B |
2 |
100% of CPU2 |
103 |
B |
3 |
100% of CPU3 |
如果cgroup A中的任务是闲置的,并没有使用CPU,那么cgroup B会借用剩余的CPU 。
如果一个cgroup设为1000,另外2个cgroup设为500,那么当第一组cgroup的进程满负荷使用CPU时,它将被限定为全部可用CPU的50%;如果此时新加一组cgroup并设定为1000时,那么第一组cgroup将只能用到全部CPU的33%,余下的cgroup使用比例为:16.5%, 16.5%, 和 33% 。
3.2.2. RT Tunable Parameters
cpu.rt_period_us
仅适用于实时调度机制, 该参数以微秒为单位指定了一个重新分配CPU的时间周期。如果一个cgroup内的任务想要在每秒周期内使用0.2秒的CPU绝对时间,需要设置cpu.rt_runtime_us为200000 及cpu.rt_period_us为1000000。
cpu.rt_runtime_us
仅适用于实时调度机制, 该参数以微秒为单位指定了一个cgroup内的任务在单位时间周期内最大可用的连续时间。如果一个cgroup内的任务想要在每秒周期内使用0.2秒的CPU绝对时间,需要设置cpu.rt_runtime_us为200000 及cpu.rt_period_us为1000000。
注意,这样的设置仅限于在单颗CPU的系统上。如果是多CPU,比如双CPU,可以设置cpu.cfs_quota_us为200000及cpu.cfs_period_us为100000。同时,不建议手动设置这2个参数,应当有系统来决定CPU的绝对时间。
3.2.3. Example Usage
测试脚本
# cat /tmp/test.sh
=============================
while :; do i=$i++; done &
=============================
观察脚本:很快CPU将被脚本跑满。
# sh /tmp/test.sh
# top
1. 限定脚本使用10%的CPU
# mkdir /cgroup/cpu/test
# echo 10000 > /cgroup/cpu/test/cpu.cfs_quota_us
//因为cpu.cfs_period_us默认值为 100000
# echo 46121 > /cgroup/cpu/test/tasks
# top
成功限定脚本的CPU使用率。
2. 按比例使用CPU
# mkdir /cgroup/cpu/blue
# mkdir /cgroup/cpu/red
# sh /tmp/test.sh
# top
# echo 47533 > /cgroup/cpu/red/tasks
# sh /tmp/test.sh
# top
# echo 4096 > blue/cpu.shares
// cpu.shares的默认值为 1024
# echo 48104 > blue/tasks
# top
成功将CPU按使用比例1:4分给2个不同的cgrou 。
以上均假设为单颗CPU。
3. 满负荷跑满多核CPU(以4核为例)
对于一个双核的CPU,如果要满负荷使用,REDHAT建议这样设置
~]# echo 200000 > /cgroup/cpu/red/cpu.cfs_quota_us
~]# echo 100000 > /cgroup/cpu/red/cpu.cfs_period_us
然而在我的4核CPU上,通过简单的测试,仍然只是跑满单核CPU
# cat cpu.cfs_period_us
100000
# echo 400000 > cpu.cfs_quota_us
# cat tasks
6056
当启动4个以上的测试脚本时,4核CPU被满负荷利用。
# cat tasks
6056
6058
6060
6062
这个子系统的配置是cpu子系统的补充,提供 CPU 资源用量的统计,时间单位都是纳秒。
CPU资源使用报告
cpuacct.usage
cgroup中所有任务的CPU使用时长(纳秒) 。
# echo 0 > /cgroup/cpuacct/cpuacct.usage
将重置报告,重新进行统计。
cpuacct.stat
cgroup中所有任务的用户和内核分别使用CPU的时长:
user — 用户所消耗的CPU 时间。
system — 系统所消耗的CPU 时间。
变量USER_HZ定义了CPU的报告时间单位。
cpuacct.usage_percpu
cgroup中所有任务使用的每个cpu的时间(纳秒)。
分配CPU及内存节点。
有一些参数是必须在移动任务到cgroup前设置的,例如,要移动一个任务到cpuset子系统,那么cpuset.cpus和cpuset.mems需要在这之前进行设置, 同时 Docker 中目前也只用到这两个。
cpuset.cpus(必选) - cgroup可使用的CPU 。如0-2,16代表 0,1,2,16这4 个CPU 。
cpuset.mems(必选) - cgroup可使用的内存节点。如0-2,16代表 0,1,2,16 这4个可用节点。
cpuset.memory_migrate(可选) - 当cpuset.mems变化时内存页上的数据是否 迁移(默认值0,不迁移;1,迁移)。
cpuset.cpu_exclusive(可选) - cgroup是否独占cpuset.cpus 中分配的cpu 。 (默认值0,共享;1,独占),如果设置为1,其他cgroup内的cpuset.cpus值不能包含有该cpuset.cpus内的值。
cpuset.mem_exclusive(可选) - 是否独占memory,(默认值0,共享;1,独 占)。
cpuset.mem_hardwall(可选) - cgroup中任务的内存是否隔离,(默认值0, 不隔离;1,隔离,每个用户的任务将拥有独立的空间)。
cpuset.memory_pressure(可选) - 只读文件。统计了该cgroup的内存压力平均值;在memory_pressure_enabled开启时自动统计更新,否则内容为0 。
cpuset.memory_pressure_enabled(可选) - cpuset.memory_pressure开关, default 0
cpuset.memory_spread_page(可选) - 文件系统的buffer是否均匀的使用该 cgroup的内存节点。(默认值0,不均匀使用;1,均匀使用。)
cpuset.memory_spread_slab(可选) - 内核是否通过cpuset的设置为输入/ 输出系统进行均匀的cache 。(默认值0,不均匀使用;1,均匀使用。)
cpuset.sched_load_balance(可选) - cgroup的cpu压力是否会被平均到 cpuset中的多个cpu上。(默认值1,启用负载均衡;0,禁用。) 注意:如果父group启用了该项,那么当前项被忽略。
cpuset.sched_relax_domain_level(可选) - cpuset.sched_load_balance的 策略 :
-1:使用系统默认值 ?
0:定期负载均衡 ?
1:实时在同一内核线程间进行负载均衡 ?
2:实时在同一内核包间负载均衡 ?
3:实时在同一cpu节点或者刀片上负载均衡 ?
4:实时在多个CPU(NUMA)节点负载均衡(“多个”猜测是指cpuset中设定的CPU)
5:实时在所有CPU(NUMA)节点负载均衡
限定cgroup内的进程是否可以访问设备。
Red Hat Enterprise Linux 6 暂不支持。
devices.allow
允许访问的设备。文件包括4个字段:type(设备类型), major(主设备号), minor(次设备号), and access(访问方式)。 格式type major:minor access_type
type
可以有3个可选值:
a — 适用所有设备,包括字符设备和块设备
b — 块设备
c — 字符设备
major, minor
可以使用具体的数字表示,也可以使用符号“*”表示所有,例如:
9:*
*:*
8:1
access
可以有3个可选值:
r — 读
w — 写
m — 创建不存在的设备
devices.deny
禁止访问的设备,格式同devices.allow 。
devices.list
报告cgroup对设备的使用情况。
只有一个属性,表示进程的状态,把 task 放到 freezer 所在的 cgroup,再把 state 改为 FROZEN,就可以暂停进程。不允许在 cgroup 处于 FROZEN 状态时加入进程。
暂停或恢复任务。
freezer.state
仅出现在非root的cgroups中, 且只有3个可选值:
FROZEN — 挂起进程。
FREEZING — 进程正在挂起中。
THAWED — 激活进程。
1. 挂起进程时,会连同子进程一同挂起。
2. 不能将进程移动到处于FROZEN状态的cgroup中。
3. 只有FROZEN和THAWED可以被写进freezer.state中, FREEZING则不能。
3.6.1. Example Usage
# cat freezer.state
THAWED
cgroup处于THAWED状态时,19651的进程使用100%的cpu在运行。
# cat tasks
19651
# echo FROZEN > freezer.state
当把19651的进程写进cgroup并使之处于FROZEN状态时,该进程已从状态“R”变为“D”。
# echo 26101 > tasks
-bash: echo: write error: Device or resource busy
试图将其他进程写进处于FROZEN状态的cgroup时,报错。
报告cgroup中的任务使用内存情况及限制对内存的使用。
默认的,在x86_64系统上,每一页的物理内存会被内存子系统会消耗掉40个字节,即便是没有任何的应用。如果要关闭掉内存子系统,可以编辑/boot/grub/grub.conf ,以root身份添加一行内容:cgroup_disable=memory 。
memory.stat
统计内存使用情况。各项单位为字节。其中:
active_anon + inactive_anon = anonymous memory + file cache for tmpfs + swap cache
active_anon + inactive_anon ≠ rss, because rss does not include tmpfs.
active_file + inactive_file = cache - size of tmpfs
memory.usage_in_bytes
当前cgroup的内存使用情况(in bytes).
memory.memsw.usage_in_bytes
当前group的内存+swap的内存使用情况(in bytes).
memory.max_usage_in_bytes
报告进程使用的最大内存(in bytes).
memory.memsw.max_usage_in_bytes
报告进程使用的最大内存+swap(in bytes).
memory.limit_in_bytes
设定最大的内存使用量,可以加单位(k/K,m/M,g/G)不加单位默认为bytes。
1:不能为root的group设定该参数。
2:子group的限制要小于父group 值。
3:-1取消限制。
memory.memsw.limit_in_bytes
设定最大的内存+swap的使用量(参见memory.limit_in_bytes)。
memory.limit_in_bytes的设置对于此选项非常重要。该值的设定应该不小于memory.limit_in_bytes的设定值。
memory.failcnt
统计达到内存限制(memory.limit_in_bytes)的次数。
memory.memsw.failcnt
统计达到内存+swap限制(memory.memsw.limit_in_bytes) 的次数。
memory.soft_limit_in_bytes
和 memory.limit_in_bytes 的差异是,这个限制并不会阻止进程使用超过限额的内存,只是在系统内存不足时,会优先回收超过限额的进程占用的内存,使之向限定值靠拢。该值应小于memory.limit_in_bytes设定值。
memory.force_empty
当设置为0时,清空该group的所有内存页;该选项只有在当前group
没有tasks才可以使用。
memory.swappiness
该group的交换分区的优先级,值低于60时优先使用物理内存,大于60时,优先使用swap。
1: 不能调整root的group的swappiness
2: 不能调整有子group的swappiness
memory.move_charge_at_immigrate
是否允许进程在group间进行迁移,1表示允许;0表示禁止。
memory.use_hierarchy
各个层次间的内存使用是否独立。默认值0,表示独立使用;当为1时,子层次中进程的内存使用会受到父层次设定值的影响。该项只能对于没有子层次的group进行设定,并且会继承父层次的设定。
memory.oom_control
当进程出现Out of Memory时,是否进行kill操作。默认值0,kill;设置为1时,进程将进入睡眠状态,等待内存充足时被唤醒。
3.7.1. Example Usage
# mkdir /cgroup/memory/blue
# cd /cgroup/memory/blue
# echo 100m > memory.limit_in_bytes
# echo $$ > tasks
# yes | awk '{mem[NR]=NR}'
当awk所使用的内存超过100M时将被kill掉。
# echo 1 > memory.oom_control
# yes | awk '{mem[NR]=NR}'
通过ps观察,当awk超过100M内存时,将进入D状态。
指定tc的handle,通过tc实现网络控制。
设置每个网络接口 ( network interface ) 的优先级。该子系统并没有像其他子系统一样编译进内核,而是需要另外加载才能使用:
# modprobe netprio_cgroup
net_prio.prioidx
一个包含唯一整数的只读文件。内核用这个数字来表示该group。
net_prio.ifpriomap
指定各个网卡的该group的优先级格式,
1:子group默认使用父group的优先级
2:值越大优先级越低
例如:
# cat /cgroup/net_prio/iscsi/net_prio.ifpriomap
eth0 5
eth1 4
一下参数会出现在已经存在的group中,而不管该group是否在使用中。
tasks
一个包含进程pid的列表,pid可能不是唯一的且没有排序。把一个进程pid写到这个文件中就表示把这个进程加入这个cgroup中。
cgroup.procs
在该cgroup的线程组ID列表。这份名单不保证是排序的或没有重复的TGID,如果需要,用户空间程序应该对它进行排序或去重。
写一个线程组ID到这个文件将这个组所有的线程加到这个cgroup中。
notify_on_release
是否在退出时运行release agent 。1 表示允许;0 表示禁止。
Root级别的cgroup默认值是0,其他子group会继承父group的设定值。
release_agent (present in the root cgroup only)
包含一个可执行的命令。一旦一个cgroup清空了所有的进程并且notify_on_release处于打开状态,内核将会执行该命令。
Example:
1. 建立一个可执行文件。
# cat /usr/local/bin/remove-empty-cpu-cgroup.sh
#!/bin/sh
rmdir /cgroup/cpu/$1
# chmod +x /usr/local/bin/remove-empty-cpu-cgroup.sh
2. 在cpu的cgroup中打开notify_on_release
# echo 1 > /cgroup/cpu/notify_on_release
3. 指定release_agent的执行命令
# echo "/usr/local/bin/remove-empty-cpu-cgroup.sh" > /cgroup/cpu/release_agent
4. 测试
# mkdir /cgroup/cpu/blue
# cat blue/notify_on_release
1
# cgexec -g cpu:blue dd if=/dev/zero of=/dev/null bs=1024k &
[1] 8623
# cat blue/tasks
8623
# kill -9 8623
# ls /cgroup/cpu/blue
ls: cannot access /cgroup/cpu/blue: No such file or directory
参考文献:
Control Groups简介 (Cgroups)-jiaogeshahaone-ChinaUnix博客
cgroup之子系统和可调参数-jiaogeshahaone-ChinaUnix博客