Linux cgroup v2 io.max 如何限制设备带宽
来源:17golang原创
时间:2026-09-12 11:05:18 435浏览 收藏
Linux 上想给某个服务限制磁盘读写,关键不是给挂载目录“限速”,而是把进程放进 cgroup v2,再在该 cgroup 的 io.max 中按块设备的 MAJ:MIN 写入上限。比如目标设备是 8:16,可以设置每秒最多读取 2 MiB、每秒最多写入 8 MiB;未配置的方向仍是 max。
最小闭环是:确认 cgroup v2 和io控制器可用,创建专用 cgroup,向io.max写入设备号与rbps/wbps,然后用io.stat和进程归属文件复查。限额到达后 I/O 会被延迟,短时突发仍可能出现。
io.max的键是设备主次号,不是/data这类路径。rbps/wbps是字节/秒,riops/wiops是 I/O 次数/秒;写max可以移除某个限制。- 验证时要同时看进程是否在目标 cgroup,以及
io.stat是否出现对应设备行。
io.max 限制的对象是设备,而不是挂载目录
cgroup v2 的资源控制是层级模型:进程先归属于一个 cgroup,控制器再针对这个层级中的资源消耗施加边界。io.max 由 I/O 控制器提供,配置行使用块设备的主设备号和次设备号,例如 8:16。因此,同一个挂载目录如果跨越多个块设备,就不能只写一个目录名来表达限制。
这个接口支持四个独立维度:rbps 和 wbps 分别限制读、写字节速率;riops 和 wiops 分别限制读、写 I/O 次数。它们可以在同一行按任意顺序组合。内核文档还特别说明,BPS 和 IOPS 按读写方向分别计量,达到限制时请求会延迟,但临时突发并不会被完全禁止。

| 字段 | 含义 | 示例 |
|---|---|---|
MAJ:MIN | 块设备主次设备号 | 8:16 |
rbps / wbps | 读 / 写字节每秒 | 2097152 |
riops / wiops | 读 / 写 I/O 次数每秒 | 120 |
max | 移除该字段的具体限制 | wiops=max |
先确认 cgroup v2 和 io 控制器
先找出统一层级挂载点,不要假定所有发行版都使用相同目录。下面的检查只读取状态;真正写入控制器前,应确认你管理的是专用层级,并了解发行版的 systemd 是否会接管该目录。
# 查看 cgroup v2 的挂载点;输出为空时先处理层级配置
findmnt -t cgroup2 -o TARGET,FSTYPE,OPTIONS
# 以常见挂载点为例,确认 io 控制器是否对父级可用
CG=/sys/fs/cgroup
cat "$CG/cgroup.controllers"
cat "$CG/cgroup.subtree_control"
# 创建专用工作负载边界;生产环境请使用明确的服务生命周期管理
mkdir -p "$CG/limited-worker"
echo "+io" > "$CG/cgroup.subtree_control"
cat "$CG/limited-worker/cgroup.controllers"
控制器是向下分配的:父级没有在 cgroup.subtree_control 启用 io,子级就不能越过父级单独启用。不同发行版可能由 systemd 维护 cgroup 树;如果手工目录和服务管理器争用同一层级,重启或重新加载服务后配置可能被覆盖,最好选定一种管理方式并记录归属。
按主次设备号写入 rbps 与 wbps
用设备文件而不是挂载路径得到 MAJ:MIN。下面以示例设备 /dev/sdb 和工作负载目录为例:读限制设为 2 MiB/s,写限制设为 8 MiB/s。数值单位是字节,不是“MiB”字符串,因此 2 MiB 要写成 2097152。
# 从块设备读取十进制主次设备号,避免凭路径猜设备
DEVICE=/dev/sdb
DEVNO=$(lsblk -no MAJ:MIN "$DEVICE")
CG=/sys/fs/cgroup/limited-worker
# 同一设备行一次写入读写字节上限;值按字节/秒计算
echo "$DEVNO rbps=2097152 wbps=8388608" > "$CG/io.max"
# 立即回读,确认未限制方向仍显示为 max
grep -F "$DEVNO" "$CG/io.max"
如果还要限制请求次数,可以在同一行加入 riops= 或 wiops=。不要把同一个键在一行中重复写入;内核文档明确指出这种结果未定义。取消单项限制时保留设备号,只把对应值改为 max:
# 只移除写字节速率限制,读限制保持不变
echo "$DEVNO wbps=max" > "$CG/io.max"
cat "$CG/io.max"
限额是 cgroup 对该设备的绝对边界,不是整块盘的性能承诺。父级已有更紧限制时,子级不能把它“放宽”;多个子 cgroup 的限额之和也不应被理解为设备一定能同时提供的吞吐量。
用 io.stat 和进程归属复查是否生效
只看到 io.max 的配置并不能证明目标服务正在受控。先把服务 PID 放入 cgroup,再检查三处:进程的 /proc/PID/cgroup、目标目录的 cgroup.procs,以及该 cgroup 的 io.stat。
# 将已经启动的工作负载迁入目标 cgroup;写入 PID 会迁移该进程的线程组
PID=12345
echo "$PID" > "$CG/cgroup.procs"
# 两种方向交叉确认进程归属
grep '0::' "/proc/$PID/cgroup"
grep -Fx "$PID" "$CG/cgroup.procs"
# 按设备查看累计读写字节与 I/O 次数
grep -F "$DEVNO" "$CG/io.stat"
io.stat 里的常见字段包括 rbytes、wbytes、rios 和 wios,设备行同样以 MAJ:MIN 标识。它适合确认统计归属和变化趋势,不应拿一次读数当成稳定带宽基准;需要判断限流效果时,应在固定负载下按时间窗口观察业务吞吐、请求延迟和 I/O 压力。

上线前保留回退和审计边界
生产变更至少记录四项:目标服务和 PID 归属、设备的 MAJ:MIN、每个读写字段的旧值与新值、回退命令。若只想撤销限制,可以对相应字段写 max;若要整体删除临时 cgroup,应先停止或迁出其中进程,再按发行版管理方式清理目录。
还要注意缓存写回的边界。内核文档说明,cgroup writeback 需要底层文件系统支持,当前明确支持 ext2、ext4、btrfs、f2fs 和 xfs;其他文件系统的写回 I/O 可能归到 root cgroup。多个 cgroup 同时修改同一个 inode 时,归属也可能不符合直觉。因此,“配置回读正确”和“业务看到的吞吐下降”是两个都要观察的结果。
最终检查可以压缩成这张清单:父级有 io、目标目录有 io.max;设备号来自实际块设备;服务 PID 出现在目标 cgroup;io.stat 有对应设备行;systemd 或其他管理器不会在重启时覆盖配置;回退值和审计记录已保存。
相关问题
io.max 能直接限制某个挂载目录吗?
不能直接按目录匹配。它按块设备主次号生效;如果目录对应多个设备,需要分别确认并配置各设备。
rbps 和 riops 应该选哪个?
需要限制总读写量时选 BPS,需要限制请求频率时选 IOPS;两者可以组合,但都应结合实际负载观察,而不是只凭设备标称值设定。
为什么 io.stat 有数据但体感没有明显限速?
先确认 PID 在目标 cgroup,再看读写是否经过页缓存、写回文件系统是否支持,以及限制是否配置在真正发生 I/O 的设备上。
如何取消一个设备的写限制?
向该 cgroup 的 io.max 写入同一设备号和 wbps=max;回读文件确认该字段恢复为 max。
参考资料
- Linux Kernel:Control Group v2,查看控制器层级、io.max 字段和 io.stat 说明。
- freedesktop.org:systemd.resource-control,了解 systemd 服务与资源控制的管理边界。
-
491 收藏
-
426 收藏
-
387 收藏
-
242 收藏
-
237 收藏
-
297 收藏
-
216 收藏
-
285 收藏
-
275 收藏
-
文章 · linux | 22小时前 | Linux · 文件系统 · 挂载 · 运维排障 · 工作目录 bind mount Linux mount --bind umount target is busy EBUSY476 收藏
-
244 收藏
-
115 收藏
-
429 收藏
-
384 收藏
-
207 收藏
-
255 收藏
-
392 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 立即学习 543次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 立即学习 516次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 立即学习 500次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 立即学习 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 立即学习 485次学习