分类: 系统运维
2014-11-20 15:55:34
1. 子系统和可调参数
3.1. blkio
blkio 子系统提供2种策略来控制访问 I/O:
权重比例。
I/O 使用上限。
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
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。
blkio.reset_stats
向该文件中写入一个整数,可以重置该 cgroup 中的统计计数。
blkio.time
统计 cgroup 对具体设备的 I/O 访问时间。内容有三个字段:major, minor 和time。time 的单位为毫秒(ms)
blkio.sectors
统计 cgroup 对具体设备的扇区读写数。内容有三个字段:major, minor 和sectors(表示磁盘的扇区数)。
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(表示操作的次数)。
blkio.io_service_bytes
统计 cgroup对具体设备的读写字节数。内容有四个字段:major, minor, operation (read, write, sync, or async)和 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硬盘也是有意义的。
blkio.io_merged
统计 cgroup 将 BIOS 请求合并到 I/O 操作请求的次数。内容有两个字段:number和 operation。
blkio.io_queued
统计I/O 操作排队的请求数。内容有两个字段:number 和 operation(read, write, sync, or async)。
blkio.throttle.io_serviced
统计 cgroup 对具体设备的读写操作数。blkio.io_serviced 与blkio.throttle.io_serviced的不同之处在于,CFQ 调度请求队列时,前者不会更新。
内容有四个字段:major, minor,operation (read, write, sync, or async)和 number(表示操作的次数)。
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(表示传输的字节数)。
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 组的,而不是针对组中单个进程的。
CPU 子系统提供2种调度方法:
Completely Fair Scheduler (CFS) — 按指定比例分配调度CPU 的使用时间。可能会有抢占CPU的情况。
Real-Time scheduler (RT) — 指定绝对时间分配CPU 。
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% 。
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的绝对时间。
测试脚本
# 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
3.3. cpuacct
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的时间(纳秒)。
3.4. cpuset
分配CPU及内存节点。
有一些参数是必须在移动任务到cgroup前设置的,例如,要移动一个任务到cpuset子系统,那么cpuset.cpus和cpuset.mems需要在这之前进行设置。
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)节点负载均衡
3.5. devices
限定cgroup内的进程是否可以访问设备。
Red Hat Enterprise Linux 6 暂不支持。
devices.allow
允许访问的设备。文件包括4个字段:type(设备类型), major(主设备号), minor(次设备号), and access(访问方式)。
type
可以有3个可选值:
a — 适用所有设备,包括字符设备和块设备
b — 块设备
c — 字符设备
major, minor
可以使用具体的数字表示,也可以使用符号“*”表示所有,例如:
9:*
*:*
8:1
access
可以有3个可选值:
r — 读
w — 写
m — 创建不存在的设备
devices.deny
禁止访问的设备,格式同devices.allow 。
devices.list
报告cgroup对设备的使用情况。
3.6. freezer
暂停或恢复任务。
.
freezer.state
仅出现在非root的cgroups中, 且只有3个可选值:
FROZEN — 挂起进程。
FREEZING — 进程正在挂起中。
THAWED — 激活进程。
1. 挂起进程时,会连同子进程一同挂起。
2. 不能将进程移动到处于FROZEN状态的cgroup中。
3. 只有FROZEN和THAWED可以被写进freezer.state中, FREEZING则不能。
# 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时,报错。
3.7. memory
报告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时,进程将进入睡眠状态,等待内存充足时被唤醒。
# 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状态。
3.8. net_cls
指定tc的handle,通过tc实现网络控制。
3.9. net_prio
设置每个网络接口 ( 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
3.10. Common Tunable Parameters
一下参数会出现在已经存在的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