块 I/O 控制器

概述

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

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

操作方法

节流/上限策略

启用块 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 文件设置写入限制。

分层 Cgroup

节流实现了分层支持;但是,只有在 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

该组向磁盘发出的 I/O (bio) 数。这些 I/O 数根据操作类型(读取或写入、同步或异步)进一步划分。前两个字段指定设备的主次编号,第三个字段指定操作类型,第四个字段指定 I/O 数。

blkio.io_service_time

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

blkio.io_wait_time

此 cgroup 的 I/O 在调度器队列中等待服务所花费的总时间。这可能大于自上次更新以来的总时间,因为它是所有 I/O 的累积 io_wait_time。它不是衡量 cgroup 等待的总时间,而是衡量其各个 I/O 的 wait_time。对于 queue_depth > 1 的设备,此指标不包括将 I/O 分派到设备后但在实际得到服务之前所花费的等待服务的时间(由于设备重新排序请求,这里可能存在时间滞后)。这是以纳秒为单位的,以使其对于闪存设备也有意义。此时间根据操作类型(读取或写入、同步或异步)进一步划分。前两个字段指定设备的主次编号,第三个字段指定操作类型,第四个字段以纳秒为单位指定 io_wait_time。

blkio.io_merged

合并到属于此 cgroup 的请求中的 bio/请求的总数。此数目根据操作类型(读取或写入、同步或异步)进一步划分。

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 中每个 I/O 在调度器队列中等待所花费的时间的累积总和。这是以纳秒为单位的。如果在 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

注意:如果为设备同时指定了带宽和 IOPS 规则,则 IO 将同时受到这两个约束的限制。

blkio.throttle.io_serviced

该组向磁盘发出的 I/O (bio) 数。这些 I/O 数根据操作类型(读取或写入、同步或异步)进一步划分。前两个字段指定设备的主次编号,第三个字段指定操作类型,第四个字段指定 I/O 数。

blkio.throttle.io_service_bytes

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

各种策略之间的通用文件

blkio.reset_stats

向此文件写入一个整数将导致重置该 cgroup 的所有统计信息。