linux 的 cgroups 还可以限制和监控进程的磁盘 io。这个功能通过 blkio 子系统实现。
blkio 子系统里东西很多。不过大部分都是只读的状态报告,可写的参数就只有下面这几个:
复制代码代码如下:
blkio.throttle.read_bps_device
blkio.throttle.read_iops_device
blkio.throttle.write_bps_device
blkio.throttle.write_iops_device
blkio.weight
blkio.weight_device
这些都是用来控制进程的磁盘 io 的。很明显地分成两类,其中带“throttle”的,顾名思义就是节流阀,将流量限制在某个值下。而“weight”就是分配 io 的权重。
“throttle”的那四个参数看名字就知道是做什么用的。拿 blkio.throttle.read_bps_device 来限制每秒能读取的字节数。先跑点 io 出来
复制代码代码如下:
dd if=/dev/sda of=/dev/null &
[1] 2750
用 iotop 看看目前的 io
复制代码代码如下:
TID PRIO USER DISK READ DISK WRITE SWAPIN IO> COMMAND
2750 be/4 root 66.76 M/s 0.00 B/s 0.00 % 68.53 % dd if=/dev/sda of=/dev/null
...
然后修改一下资源限制,把进程加入控制组
复制代码代码如下:
echo '8:0 1048576' >/sys/fs/cgroup/blkio/foo/blkio.throttle.read_bps_device
echo 2750 >/sys/fs/cgroup/blkio/foo/tasks
这里的 8:0 就是对应块设备的主设备号和副设备号。可以通过 ls -l 设备文件名查看。如
复制代码代码如下:
# ls -l /dev/sda
brw-rw----. 1 root disk 8, 0 Oct 24 11:27 /dev/sda
这里的 8, 0 就是对应的设备号。所以,cgroups 可以对不同的设备做不同的限制。然后来看看效果
复制代码代码如下:
TID PRIO USER DISK READ DISK WRITE SWAPIN IO> COMMAND
2750 be/4 root 989.17 K/s 0.00 B/s 0.00 % 96.22 % dd if=/dev/sda of=/dev/null
...
可见,进程的每秒读取立马就降到了 1MB 左右。要解除限制,写入如 “8:0 0” 到文件中即可
不过需要注意的是,这种方式对小于采样间隔里产生的大量 io 是没用的。比如,就算在 1s 内产生一个每秒写入 100M 的峰值,也不会因此被限制掉。
再看看 blkio.weight 。blkio 的 throttle 和 weight 方式和 cpu 子系统的 quota 和 shares 有点像,都是一种是绝对限制,另一种是相对限制,并且在不繁忙的时候可以充分利用资源,权重值的范围在 10 – 1000 之间。
测试权重方式要麻烦一点。因为不是绝对限制,所以会受到文件系统缓存的影响。如在虚拟机中测试,要关闭虚机如我用的 VirtualBox 在宿主机上的缓存。如要测试读 io 的效果,先生成两个几个 G 的大文件 /tmp/file_1,/tmp/file_2 ,可以用 dd 搞。然后设置两个权重
复制代码代码如下:
# echo 500 >/sys/fs/cgroup/blkio/foo/blkio.weight
# echo 100 >/sys/fs/cgroup/blkio/bar/blkio.weight
测试前清空文件系统缓存,以免干扰测试结果
复制代码代码如下:
sync
echo 3 >/proc/sys/vm/drop_caches
在这两个控制组中用 dd 产生 io 测试效果。
复制代码代码如下:
# cgexec -g "blkio:foo" dd if=/tmp/file_1 of=/dev/null &
[1] 1838
# cgexec -g "blkio:bar" dd if=/tmp/file_2 of=/dev/null &
[2] 1839
还是用 iotop 看看效果
复制代码代码如下:
TID PRIO USER DISK READ DISK WRITE SWAPIN IO> COMMAND
1839 be/4 root 48.14 M/s 0.00 B/s 0.00 % 99.21 % dd if=/tmp/file_2 of=/dev/null
1838 be/4 root 223.59 M/s 0.00 B/s 0.00 % 16.44 % dd if=/tmp/file_1 of=/dev/null
参数说明
可设置的参数:
- blkio.weight
说明:指定 cgroup 默认可用 IO 的比例(加权),值的范围为 100 至 1000。该值可由具体设备的 blkio.weight_device 参数覆盖。
示例:设置 cgroup lv0 的默认加权为 500:cgset -r blkio.weight=100 lv0
- blkio.weight_device
说明:指定 cgroup 中指定设备的可用 IO 比例(加权),范围是 100 至 1000。该值的的格式为 major:minor weight ,其中 major 和 minor 参考文档 Linux 分配的设备。
示例:设置 cgroup lv0 对 /dev/sda 的加权为 500:cgset -r blkio.weight_device="8:0 500" lv0
- blkio.throttle.read_bps_device / blkio.throttle.write_bps_device
说明:指定 cgroup 中某设备每秒钟读/写数据的字节上限。其格式为 major:minor bytes_per_second。
示例:设置 cgroup lv0 在 /dev/sdc 上每秒最多读 10KiB 数据:cgset -r blkio.throttle.read_bps_device="8:32 10240" lv0
- blkio.throttle.read_iops_device / blkio.throttle.write_iops_device
说明:指定 cgroup 中某设备每秒钟可以执行的读/写请求数上限。其格式为major:minor operations_per_second。
示例:设置 cgroup lv0 在 /dev/sdc 上每秒最多执行 1000 次读请求:cgset -r blkio.throttle.read_iops_device="8:32 1000" lv0
报告参数:
- blkio.time
报告 cgroup 对具体设备的 I/O 访问时间。条目有三个字段:major, minor 和time。time 的单位为毫秒(ms) - blkio.sectors
报告 cgroup 对具体设备的扇区读写数。条目有三个字段:major, minor 和sectors。 - blkio.io_service_bytes
报告 cgroup 对具体设备的读写字节数。条目有四个字段:major, minor, operation和 bytes。其中 operation 表示操作类型,包括 read, write, sync 和 async。 - blkio.io_serviced
报告 cgroup 对具体设备的 I/O 操作数。条目有四个字段:major, minor, operation和 number。 - 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)。 - blkio.io_merged
报告 cgroup 将 BIOS 请求合并到 I/O 操作请求的次数。条目有两个字段:number和 operation。 - blkio.io_queued
报告 cgroup 为 I/O 操作排队的请求次数。条目有两个字段:number 和 operation。 - blkio.throttle.io_service_bytes
报告 cgroup 限流对具体设备的读写字节数。blkio.io_service_bytes 与blkio.throttle.io_service_bytes 的不同之处在于,CFQ 调度请求队列时,前者不会更新。条目有四个字段:major, minor, operation 和 bytes。 - blkio.throttle.io_serviced
报告 cgroup 限流对具体设备的读写操作数。条目有四个字段:major, minor,operation 和 number。 - blkio.reset_stats
向该文件中写入一个整数,可以重置该 cgroup 中的报告计数。
blkio子系统使用心得
- 查看一个设备的 major 和 minor 可以使用:
ls -l /dev/DEV
例如,要查看 /dev/dm-0 的 major 和 minor:~ ] # ls -l /dev/dm-0
brw -rw ---- 1 root disk 253 , 0 Dec 3 01:02 /dev /dm - 0其中
253, 0
即为 /dev/dm-0 的 major, minor - blkio.throttle.* 的限制是针对整个 cgroup 组的,而不是针对组中单个进程的。
例如,当设置 lv0blkio.throttle.write_bps_device="253:0 1048576"
时,整个 lv0 组内所有进程向 /dev/dm-0 的写入速率之和不能超过 1 MiB/秒。 - 经测试,对某个进程的 blkio 限制有可能影响 Cgroup 之外的进程。复现方法:
/dev/sdb + /dev/sdc 做 flashcache,设置 lv0blkio.throttle.write_bps_device="8:32 1048576"
,即限制 lv0 内的进程对 /dev/sdc 的写入速率为 1MiB/秒,然后使用cgexec -g blkio:lv0 dd if=/dev/zero of=/data0/testfile1 bs=10240 count=100000
启动一个在 lv0 限制下的 dd 向 flashcache 写文件。dd 很快便完成,但使用 iostat 观察,发现 /dev/sdc 的写入受 cgroup 限制,只有 1MiB/秒。这时我们再直接执行一个 dd:dd if=/dev/zero of=/data0/testfile1 bs=10240 count=100000
,再使用 iostat 查看磁盘 IO 状态,/dev/sdc 写入速率仍然是 1MiB/秒,也就是说后面一个 dd 虽不在 cgroup lv0 限制之内,却也受到了 lv0 限流的影响。 - 进程对 pagecache 的读写操作不受 blkio.throttle.* 限制。