cgroup blkio仅对Direct I/O(如O_DIRECT、MySQL direct_io)有效,对Buffered I/O无效;需指定设备号、同时设置bps和iops,并通过docker参数或手动写cgroup文件实现限速。

直接用cgroup blkio做磁盘IO带宽限制,关键在选对设备、设对参数、避开Buffered I/O的盲区。它不是万能限速器,而是专为Direct I/O设计的精准阀门。
明确适用场景:先看你的IO是不是“直达车”
blkio对Direct I/O(如O_DIRECT打开文件、MySQL InnoDB开启direct_io)能实现强限制;对常规read/write这类Buffered I/O,效果有限——因为数据先进PageCache,后续刷盘由内核统一调度,blkio管不到那段路径。
- 数据库类服务(PostgreSQL、MongoDB默认配置,或MySQL调了innodb_flush_method=O_DIRECT)适合用blkio控读写带宽
- 日志归档脚本、备份工具(如rsync加--inplace或dd用oflag=direct)也符合Direct I/O特征
- 普通shell重定向(> file)、tail -f、标准cp命令基本走Buffered I/O,单独配blkio意义不大,需配合vm.dirty_ratio等内核参数协同调控
实操带宽限制:三步写对控制文件
所有操作基于cgroup v1(主流Docker/K8s仍默认使用),路径为/sys/fs/cgroup/blkio/:
- 创建子组:
mkdir /sys/fs/cgroup/blkio/db-limited - 指定设备与限速值(以/dev/sda为例):
echo "8:0 52428800" > /sys/fs/cgroup/blkio/db-limited/blkio.throttle.write_bps_device
表示对主设备号8、次设备号0(即sda)限制写入带宽为50MB/s(52428800字节/秒) - 把进程PID加入:
echo 12345 > /sys/fs/cgroup/blkio/db-limited/cgroup.procs
注意:设备号可用ls -l /dev/sd*查,如brw-rw---- 1 root disk 8, 0 Mar 10 /dev/sda,其中8,0就是主次设备号。
IOPS与吞吐量要分开控,不能只盯一个数
高IOPS(小块随机读写)和高吞吐量(大块顺序读写)对磁盘压力机制不同。单设bps可能压不住突发IOPS,单设iops又可能放行超大IO请求占满带宽:
- 同时设置更稳妥:
echo "8:0 1000" > /sys/fs/cgroup/blkio/db-limited/blkio.throttle.write_iops_device(写IOPS上限1000次/秒)echo "8:0 104857600" > /sys/fs/cgroup/blkio/db-limited/blkio.throttle.read_bps_device(读带宽上限100MB/s) - 测试验证用
dd if=/dev/zero of=/mnt/test bs=4k count=10000 oflag=direct(强制Direct I/O),再用iostat -x 1观察%util和r/s、w/s是否被卡在设定值附近
容器环境直接用Docker参数更省事
Docker封装了blkio底层操作,启动时加参数即可,无需手动挂cgroup目录:
- 限制某容器对/dev/sda的读带宽为30MB/s、写IOPS为500:
docker run --device-read-bps /dev/sda:30mb --device-write-iops /dev/sda:500 nginx - 支持多设备分别限速,例如同时控sda和nvme0n1:
--device-read-bps /dev/sda:20mb --device-read-bps /dev/nvme0n1:100mb - 运行中调整需用
docker update,但仅支持bps类参数,iops类不支持热更新










