块 I/O 控制器

概述

cgroup 子系统 “blkio” 实现了块 I/O 控制器。存储层次结构中的叶节点和中间节点似乎都需要各种 I/O 控制策略(如比例带宽、最大带宽)。计划使用相同的基于 cgroup 的管理界面来管理 blkio 控制器,并根据用户选项在后台切换 I/O 策略。

一种 I/O 控制策略是节流策略,可用于指定设备上的 I/O 速率上限。此策略在通用块层中实现,可用于叶节点以及更高级别的逻辑设备(如设备映射器)。

HOWTO

节流/上限策略

启用块 I/O 控制器

CONFIG_BLK_CGROUP=y

在块层中启用节流

CONFIG_BLK_DEV_THROTTLING=y

挂载 blkio 控制器(参见 控制组,为什么需要 cgroup?)

mount -t cgroup -o blkio none /sys/fs/cgroup/blkio

为根组指定特定设备上的带宽速率。策略的格式为“<major>:<minor> <bytes_per_second>”

echo "8:16  1048576" > /sys/fs/cgroup/blkio/blkio.throttle.read_bps_device

这将限制主/次设备号为 8:16 的根组的读取速度为 1MB/秒。

运行 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

节流实现层次结构支持;但是,只有在 cgroup 端启用 “sane_behavior” 时,才会启用节流的层次结构支持,这目前是一个开发选项,尚未公开提供。

如果有人创建如下层次结构

   root
   /  \
test1 test2
   |
test3

带有 “sane_behavior” 的节流将正确处理层次结构。对于节流,所有限制都适用于整个子树,而所有统计信息都特定于该 cgroup 中任务直接生成的 I/O。

如果 cgroup 端未启用 “sane_behavior” 的节流实际上会将同一级别的所有组视为如下所示

        pivot
     /  /   \  \
root  test1 test2  test3

各种用户可见的配置选项

CONFIG_BLK_CGROUP

块 I/O 控制器。

CONFIG_BFQ_CGROUP_DEBUG

调试帮助。如果启用此选项,则一些额外的统计文件会显示在 cgroup 中。

CONFIG_BLK_DEV_THROTTLING

在块层中启用块设备节流支持。

cgroup 文件的详细信息

比例权重策略文件

blkio.bfq.weight

指定每个 cgroup 的权重。这是该组在所有设备上的默认权重,直到被每个设备的规则覆盖(参见下面的 blkio.bfq.weight_device)。

目前允许的权重范围为 1 到 1000。有关更多详细信息,请参见 BFQ(预算公平排队)

blkio.bfq.weight_device

指定每个 cgroup 每个设备的权重,从而覆盖默认的组权重。有关更多详细信息,请参见 BFQ(预算公平排队)

以下是格式

# echo dev_maj:dev_minor weight > blkio.bfq.weight_device

在此 cgroup 中配置 /dev/sdb (8:16) 上的 weight=300

# echo 8:16 300 > blkio.bfq.weight_device
# cat blkio.bfq.weight_device
dev     weight
8:16    300

在此 cgroup 中配置 /dev/sda (8:0) 上的 weight=500

# echo 8:0 500 > blkio.bfq.weight_device
# cat blkio.bfq.weight_device
dev     weight
8:0     500
8:16    300

删除此 cgroup 中 /dev/sda 的特定权重

# echo 8:0 0 > blkio.bfq.weight_device
# cat blkio.bfq.weight_device
dev     weight
8:16    300
blkio.time

每个设备分配给 cgroup 的磁盘时间,以毫秒为单位。前两个字段指定设备的主设备号和次设备号,第三个字段指定分配给组的磁盘时间,以毫秒为单位。

blkio.sectors

该组传输到/从磁盘的扇区数。前两个字段指定设备的主设备号和次设备号,第三个字段指定该组传输到/从设备的扇区数。

blkio.io_service_bytes

该组传输到/从磁盘的字节数。这些字节数按操作类型进一步划分 - 读取或写入、同步或异步。前两个字段指定设备的主设备号和次设备号,第三个字段指定操作类型,第四个字段指定字节数。

blkio.io_serviced

该组发往磁盘的 IO(bio)数量。这些 IO 按操作类型进一步划分 - 读取或写入、同步或异步。前两个字段指定设备的主设备号和次设备号,第三个字段指定操作类型,第四个字段指定 IO 数量。

blkio.io_service_time

此 cgroup 完成的 IO 请求分发和请求完成之间的总时间。单位为纳秒,使其对闪存设备也有意义。对于队列深度为 1 的设备,此时间表示实际的服务时间。当 queue_depth > 1 时,情况不再如此,因为请求可能会乱序处理。这可能会导致给定 IO 的服务时间包括多个 IO 的服务时间(乱序处理时),这可能会导致总 io_service_time > 实际经过的时间。此时间按操作类型进一步划分 - 读取或写入、同步或异步。前两个字段指定设备的主设备号和次设备号,第三个字段指定操作类型,第四个字段指定 io_service_time,单位为纳秒。

blkio.io_wait_time

此 cgroup 的 IO 在调度程序队列中等待服务的总时间。这可能大于经过的总时间,因为这是所有 IO 的累积 io_wait_time。它不是衡量 cgroup 总等待时间的指标,而是衡量其各个 IO 的 wait_time 的指标。对于 queue_depth > 1 的设备,此指标不包括将 IO 分派到设备后直到实际被服务的时间(由于设备对请求的重新排序,这里可能存在时间延迟)。单位为纳秒,使其对闪存设备也有意义。此时间按操作类型进一步划分 - 读取或写入、同步或异步。前两个字段指定设备的主设备号和次设备号,第三个字段指定操作类型,第四个字段指定 io_wait_time,单位为纳秒。

blkio.io_merged

合并到属于此 cgroup 的请求中的 bios/请求总数。按操作类型进一步划分 - 读取或写入、同步或异步。

blkio.io_queued

在任何给定时刻为此 cgroup 排队的请求总数。按操作类型进一步划分 - 读取或写入、同步或异步。

blkio.avg_queue_size

仅在 CONFIG_BFQ_CGROUP_DEBUG=y 时启用调试辅助。此 cgroup 的整个生存期内的平均队列大小。每次此 cgroup 的队列之一获得时间片时,都会采集队列大小样本。

blkio.group_wait_time

仅在 CONFIG_BFQ_CGROUP_DEBUG=y 时启用调试辅助。这是 cgroup 从繁忙状态(即,从 0 到 1 个请求排队)到为其队列之一获取时间片所必须等待的时间量。这与 io_wait_time 不同,后者是该 cgroup 中每个 IO 在调度程序队列中等待所花费的时间的累积总数。单位为纳秒。如果在 cgroup 处于等待(时间片)状态时读取此数据,则该统计信息将仅报告累积到上次获取时间片为止的 group_wait_time,并且不包括当前增量。

blkio.empty_time

仅在 CONFIG_BFQ_CGROUP_DEBUG=y 时启用调试辅助。这是 cgroup 在没有挂起请求时未被服务所花费的时间量,即,它不包括为 cgroup 的队列之一空闲所花费的任何时间。单位为纳秒。如果在 cgroup 处于空闲状态时读取此数据,则该统计信息将仅报告累积到上次有挂起请求为止的 empty_time,并且不包括当前增量。

blkio.idle_time

仅在 CONFIG_BFQ_CGROUP_DEBUG=y 时启用调试辅助。这是 IO 调度程序在给定 cgroup 上空闲所花费的时间量,以等待比来自其他队列/cgroup 的现有请求更好的请求。单位为纳秒。如果在 cgroup 处于空闲状态时读取此数据,则该统计信息将仅报告累积到上次空闲期间为止的 idle_time,并且不包括当前增量。

blkio.dequeue

仅在 CONFIG_BFQ_CGROUP_DEBUG=y 时启用调试辅助。这给出了有关组从设备的服务器树中出列的次数的统计信息。前两个字段指定设备的主设备号和次设备号,第三个字段指定组从特定设备出列的次数。

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

该组发往磁盘的 IO(bio)数量。这些 IO 按操作类型进一步划分 - 读取或写入、同步或异步。前两个字段指定设备的主设备号和次设备号,第三个字段指定操作类型,第四个字段指定 IO 数量。

blkio.throttle.io_service_bytes

该组传输到/从磁盘的字节数。这些字节数按操作类型进一步划分 - 读取或写入、同步或异步。前两个字段指定设备的主设备号和次设备号,第三个字段指定操作类型,第四个字段指定字节数。

各种策略之间的通用文件

blkio.reset_stats

将 int 写入此文件将导致重置该 cgroup 的所有统计信息。