前言
Linux之父曾说过read the fucking source code。在学习linux的过程中,我觉得read the fucking document也非常的重要,今天又花了几个小时的时间,翻译了一下blkio-controller.txt,对cgroup如何控制IO有了大概的一个了解,当然有些细节还需要进一步的验证,我会继续努力。
翻译
Block IO 控制
===================
概述
========
cgroup子系统“blkio”实现块io控制器。在存储层次结构中叶节点和中间节点,
似乎需要各种IO控制策略(如比例BW(bandwidth)、最大BW)
计划:为blkio控制器使用基于cgroup的相同管理接口,并基于用户选项在后台切换IO策略。
目前实现了两个IO控制策略。
第一个是成比例的基于权重时间的磁盘分区策略。它在CFQ中实现。因此
此策略仅在使用CFQ时对叶节点生效。
第二个是一种是限制策略,可用于指定在设备上IO速率上限。
此策略在通用块层中实现,可以是用于叶节点以及更高级别的逻辑设备,如设备映射器。
怎么做
=====
1.带宽比例权分
-----------------------------------------
你可以做一个简单的测试,跑两个运行dd线程在不同的cgroups, 这里就是你能做的。
- 开启Block IO控制
CONFIG_BLK_CGROUP=y
- 开启group scheduling在CFQ调度算法中
CONFIG_CFQ_GROUP_IOSCHED=y
- 编译启动进入kernel挂在IO controller (blkio); 参考文档cgroups.txt, 为什么cgroups是必须的?.
mount -t tmpfs cgroup_root /sys/fs/cgroup
mkdir /sys/fs/cgroup/blkio
mount -t cgroup -o blkio none /sys/fs/cgroup/blkio
- 创建两个cgroups
mkdir -p /sys/fs/cgroup/blkio/test1/ /sys/fs/cgroup/blkio/test2
- 设置test1和test2两个组的权重
echo 1000 > /sys/fs/cgroup/blkio/test1/blkio.weight
echo 500 > /sys/fs/cgroup/blkio/test2/blkio.weight
- 创建两个相同文件的大小 (512MB)在同一个硬盘上(file1, file2),启动两个dd线程在不同的cgroup读取文件
sync
echo 3 > /proc/sys/vm/drop_caches
dd if=/mnt/sdb/zerofile1 of=/dev/null &
echo $! > /sys/fs/cgroup/blkio/test1/tasks
cat /sys/fs/cgroup/blkio/test1/tasks
dd if=/mnt/sdb/zerofile2 of=/dev/null &
echo $! > /sys/fs/cgroup/blkio/test2/tasks
cat /sys/fs/cgroup/blkio/test2/tasks
在宏观层面,第一个dd应该先完成。为了获得更精确的数据,我们可以查看test1和test2组中的
blkio.disk_time和blkio.disk_扇区文件。可以说明磁盘时间(以毫秒为单位),多少个扇区
发送到磁盘。我们提供公平的磁盘时间,所以理想情况下,cgroup的io.disk_时间应与权重成比例。
限制(throttling)/上限策略
-----------------------------
- 开启Block IO控制
CONFIG_BLK_CGROUP=y
- 开启限制在block layer
CONFIG_BLK_DEV_THROTTLING=y
- 挂在IO controller (blkio); 参考文档cgroups.txt, 为什么cgroups是必须的?.
mount -t cgroup -o blkio none /sys/fs/cgroup/blkio
- 为root group,指定特定设备上的带宽速率。
策略格式"<major>:<minor> <bytes_per_second>"
echo "8:16 1048576" > /sys/fs/cgroup/blkio/blkio.throttle.read_bps_device
上面会限速1MB/s,root group在8:16设备上发生读操作
- 运行dd读取文件,就看看读的速度是不是被限制在1MB/s
# dd iflag=direct if=/mnt/common/zerofile of=/dev/null bs=4K count=1024
1024+0 records in
1024+0 records out
4194304 bytes (4.2 MB) copied, 4.0001 s, 1.0 MB/s
写的速度限制可以设置在blkio.throttle.write_bps_device文件
Cgroups层级
====================
CFQ和限制(throttling)都支持实现层次结构;但是,如果"sane_behavior"是从cgroup端启用,当前是一个开发选项,并且
不公开。
如果某人创建以下的层级:
root
/ \
test1 test2
|
test3
默认的CFQ和限制(throttling)使用"sane_behavior"将处理层次结构正确。有关CFQ层次结构支持的详细信息,
请参阅文档/block/cfq-iosched.txt。对于限制(throttling),所有限制都适用对整个子树,而所有统计数据
都会在cgroup中的task直接生成IO。
如果不从cgroup端启用"sane_behavior",限制(throttling)实际上对待所有组一个级别
pivot
/ / \ \
root test1 test2 test3
各种用户可见的配置选项
===================================
CONFIG_BLK_CGROUP
- Block IO controller的总开关.
CONFIG_DEBUG_BLK_CGROUP
- 如果开启这个选项
CONFIG_CFQ_GROUP_IOSCHED
- 开启CFQ中的分组调度,目前只支持创建一级的组
CONFIG_BLK_DEV_THROTTLING
- 开启block layer中的块设备的限制(throttling)
cgroup文件的详细信息
=======================
比例权重策略文件
--------------------------------
- blkio.weight
- 指出每一个cgroup的权重,所有设备上用同一个权重值,除非每个设备写一个规则覆盖
(看blkio.weight_device).
当前允许的权重从10到1000.
- blkio.weight_device
- 指出每一个cgroup每一个设备的权重使用这个接口
这些规则将会覆盖blkio.weight
格式如下:
# echo dev_maj:dev_minor weight > blkio.weight_device
为这个cgroup在设备/dev/sdb (8:16)配置weight=300
# echo 8:16 300 > blkio.weight_device
# cat blkio.weight_device
dev weight
8:16 300
为这个cgroup在设备/dev/sdb (8:0)配置weight=500
# echo 8:0 500 > blkio.weight_device
# cat blkio.weight_device
dev weight
8:0 500
8:16 300
移除这个cgroup在设备/dev/sdb (8:0)配置的weight
# echo 8:0 0 > blkio.weight_device
# cat blkio.weight_device
dev weight
8:16 300
- blkio.leaf_weight[_device]
- blkio.weight[_device]价值在于为了决定多少权重任务在给定的cgroup,并且和子cgroup有竞争关系
关于细节,请参考文档/block/cfq-iosched.txt。
- blkio.time
- 分配给每个设备的cgroup的磁盘时间(毫秒)。
首先两个字段指定设备的主要和次要编号,第三个字段指定分配给组的磁盘时间毫秒。
- blkio.sectors
- 当前group传输到/从磁盘的扇区数。
首两个字段指定设备的主要和次要编号,第三个字段指定传输到/从磁盘的扇区数。
- blkio.io_service_bytes
- 当前group传输到/从磁盘传输的字节数。这些按操作类型进一步划分-读或写、同步或者异步。
前两个字段指定设备的主要和次要编号,第三个字段指定操作类型和第四个字段指定字节数。
- blkio.io_serviced
- 当前group发给磁盘的IOs(bio)数。这些按操作类型进一步划分-读或写、同步或者异步。
前两个字段指定设备的主要和次要编号,第三个字段指定操作类型和第四个字段指定操作的数量。
- blkio.io_service_time
- 当前group所做的IOs从请求发送到请求完成之间的总时间量。以纳秒计算对闪存设备也有意义。
当队列深度为1的设备,此时间表示实际服务时间。当队列深度大于1时,这不再是正确的,
因为请求可能会被无序地送达。这个时间将会包括多个IO的服务时间,当服务不正常时,可能会导致
io_service_time大于实际运行时间。这个时间按操作类型进一步划分、同步或者异步
前两个字段指定设备的主要和次要编号,第三个字段指定操作类型,第四个字段指定服务时间(ns)。
- blkio.io_wait_time
- 当前group的IOs在服务调度队列花费的等待时间,这可能大于总时间已用,因为它是所有io的累计io等待时间。
它不是衡量cgroup等待的总时间,而是衡量等待其个别IOs的时间。对于队列深度大于1的设备此指标不包括
等待服务一次所花费的时间IO被发送到设备,但直到它真正得到服务(由于设备)。这是以纳秒为单位的,
以使它对flash有意义设备也是。这个时间是按操作类型进一步划分,读或写,同步或异步。
前两个字段指定设备的主要和次要编号,第三个字段指定操作类型
第四个字段以ns为单位指定io_wait_时间。
- blkio.io_merged
- 合并到属于这个cgroup的requests的bios/requests总数
按操作类型进一步划分,读或写,同步或异步
- blkio.io_queued
- 当前cgroup,在任何给定时刻排队的请求总数。
按操作类型进一步划分,读或写,同步或异步
- blkio.avg_queue_size
- 仅会在CONFIG_DEBUG_BLK_CGROUP=y启用调试辅助
在此期间,此cgroup的平均队列大小。 队列大小事例被用于得到每次此cgroup的队列获取时间间隔
- blkio.group_wait_time
- 仅会在CONFIG_DEBUG_BLK_CGROUP=y启用调试辅助
这是cgroup自忙起必须等待的时间(即,从0到排队的1个请求)获取其中一个的时间间隔
给它的队列。这不同于io_wait_time,后者是该cgroup中每个io在调度程序队列中等待的时间的累计总和。
以纳秒为单位。 如果在cgroup处于等待态时读取此值, 统计将只报告组等待时间累计到最后一次
已获取时间间隔,将不包括当前增量
- blkio.empty_time
- 仅会在CONFIG_DEBUG_BLK_CGROUP=y启用调试辅助
这是cgroup在未被服务时,在没有任何挂起的请求的情况下花费的时间量, 即, 不包括任何时间
为cgroup的某个队列花费的空闲时间. 以纳秒为单位,如果在cgroup处于空状态时读取此值,
统计将只报告在上次有一个挂起的请求之前累积的空时间,而不包括当前的增量
- blkio.idle_time
- 仅会在CONFIG_DEBUG_BLK_CGROUP=y启用调试辅助
这是时间的总计,给定cgroup中,IO调度程序比现有请求更好的请求其他队列/cgroup中的而空闲的时间量。
以纳秒为单位,如果在cgroup处于空闲状态时读取此值,统计将只报告到最后一个空闲周期为止累积的空闲时间,而不包括当前增量。
- blkio.dequeue
- 仅会在CONFIG_DEBUG_BLK_CGROUP=y启用调试辅助 This
提供从设备的服务树有关一个组退出队列的次数的统计信息
前两个字段指定设备的主要和次要编号,第三个字段指定退出队列的次数
- blkio.*_recursive
- 各种统计数据的递归版本。这些文件显示与它们的非递归对应项相同的信息,
但是包括所有子cgroup的统计信息。
限制/上限策略文件
-----------------------------------
- blkio.throttle.read_bps_device
- 指定设备读取速率的上限。IO速率为以字节/秒为单位指定。
规则是针对每个设备的。以下是格式。
echo "<major>:<minor> <rate_bytes_per_second>" > /cgrp/blkio.throttle.read_bps_device
- blkio.throttle.write_bps_device
- 指定设备写入速率的上限。IO速率为以字节/秒为单位指定。
规则是针对每个设备的。以下是格式。
echo "<major>:<minor> <rate_bytes_per_second>" > /cgrp/blkio.throttle.write_bps_device
- blkio.throttle.read_iops_device
- 指定设备读取速率的上限。IO速率为以每秒IO为单位指定。
规则是针对每个设备的。以下是格式。
echo "<major>:<minor> <rate_io_per_second>" > /cgrp/blkio.throttle.read_iops_device
- blkio.throttle.write_iops_device
- 指定设备写入速率的上限。IO速率为以每秒IO为单位指定。
规则是针对每个设备的。以下是格式。
echo "<major>:<minor> <rate_io_per_second>" > /cgrp/blkio.throttle.write_iops_device
注意:如果为设备同时指定了BW和IOPS规则,则IO是同时受到两方面的限制。
- blkio.throttle.io_serviced
- 按组分到的磁盘的IOs(bio)数. 这个按操作类型进一步划分、同步或者异步
首先两个字段指定设备的主要和次要编号,
第三个字段指定操作类型
第四个字段指定IOs数
- blkio.throttle.io_service_bytes
- 按组传输到/从磁盘传输的字节数. 这个按操作类型进一步划分、同步或者异步
首先两个字段指定设备的主要和次要编号,
第三个字段指定操作类型
第四个字段指定字节数
各种策略之间的公共文件
-----------------------------------
- blkio.reset_stats
- 将int值写入此文件将导致重置这个组的所有统计信息。
CFQ sysfs 调整
=================
/sys/block/<disk>/queue/iosched/slice_idle
------------------------------------------
在更快的硬件上,CFQ可能会很慢,特别是在连续工作负载的情况下。这是因为CFQ在单个队列上空闲,
而单个队列可能不驱动更深的请求队列深度以保持存储繁忙。
在这种情况下可以尝试设置slice_idle=0,这将把CFQ切换到IOPS(每秒IO操作)模式在支持NCQ的硬件。
这意味着CFQ不会在CFQ组和CFQ队列之间空闲,因此能够驱动更高的队列深度,获得更好的吞吐量。
那也意味着cfq在IOPS方面提供了组间的公平性,而不是在磁盘时间条款。
对于SSD设备,可以将这个值设为 0(我自己查的资料)
/sys/block/<disk>/queue/iosched/group_idle
------------------------------------------
如果通过设置slice_idle=0禁用单个cfq队列和cfq服务树上的空闲
,group_idle启动。这意味着CFQ仍将处于闲置状态,试图在群体间提供公平。
默认,group_idle和slice_idle一样,在slice_idle开启的情况下,什么都不做
如果您创建了多个组,将驱动力不足的应用程序放入该组IO使磁盘保持忙碌,总吞吐量可能会下降。
在这种情况下,设置group_idle=0,CFQ将不空闲对单个组和吞吐量应该提高。
网友评论