如何通过Cgroup在Linux中设置高频日志进程的每秒IOPS读取上限?
- 内容介绍
- 文章标签
- 相关推荐
本文共计945个文字,预计阅读时间需要4分钟。
在Linux中,使用`cgroup`机制可以对进程的资源使用进行限制。例如,`cgroup`本身不直接提供`read_iops`这样的原生控制器(尽管在cgroup v1中存在)。但是,可以通过`blkio`子系统(在cgroup v1中)或更现代的`io`控制器(在cgroup v2中)对块设备I/O进行限制,包括限制读取操作的IOPS(每秒IO次数)。
若未对频繁的日志读取进程(如使用`tail -f`、grep日志、日志收集agent等)进行限制,可能会导致磁盘带宽被过度占用,影响关键服务的性能。以下是一些基于实际应用的可行方案:
确认使用 cgroup 版本并启用 io 控制器
现代发行版(如 CentOS 8+/RHEL 8+、Ubuntu 20.04+)默认启用 cgroup v2。需确认:
- 运行
mount | grep cgroup,若看到type cgroup2即为 v2; - cgroup v2 的
io控制器支持按设备设置io.max,其中可指定rps(read operations per second)——这正是你所需的read_iops限制; - 确保内核启用了
CONFIG_CGROUP_IO(主流发行版默认开启)。
使用 cgroup v2 设置 per-device 读 IOPS 上限
以限制进程对 /dev/sda 的读 IOPS 为 100 次/秒为例(需 root 权限):
- 创建控制组:
mkdir -p /sys/fs/cgroup/logreader; - 写入设备+限速规则(格式:
<major>:<minor> rps=<value>):echo "8:0 rps=100" > /sys/fs/cgroup/logreader/io.max(8:0是/dev/sda的主次设备号,用ls -l /dev/sda查看); - 将目标进程加入该组:
echo <PID> > /sys/fs/cgroup/logreader/cgroup.procs; - 验证:向该组写入任意值后,检查
cat /sys/fs/cgroup/logreader/io.stat中是否出现rqos相关统计,且读请求被节流。
对日志读取进程做自动化管控(推荐实践)
避免手动绑 PID,建议结合 systemd 或启动脚本实现持久化控制:
- 若用 systemd 启动日志工具(如 filebeat、fluent-bit),在 service 文件中添加:
IOReadBandwidthMax=/dev/sda 100(单位:IOPS,systemd 245+ 支持); - 或在启动前通过
cgexec(需安装libcgroup-tools):cgexec -g io:/logreader your-log-reader-command; - 注意:cgroup v2 要求进程及其所有子进程都在同一控制组内,否则子进程可能逃逸限速。
验证与调优要点
单纯设限不等于生效,需实测确认:
- 用
iostat -x 1观察r/s(read requests per second)是否稳定在设定值附近; - 用
dd if=/path/to/big.log bs=4k count=100000 | wc模拟突发读,看是否被平滑压制; - 注意:rps 限制是“设备级”而非“文件级”,若日志分散在多个磁盘,需分别配置;
- 若进程使用 direct I/O(如某些日志 agent 开启
O_DIRECT),部分内核版本下 rps 限速可能不生效,此时需改用bps(带宽)限制作为补充。
不复杂但容易忽略的是设备号匹配和 cgroup 版本一致性。只要路径、设备号、控制器启用三者到位,read_iops 级别的硬性限制就能可靠落地。
本文共计945个文字,预计阅读时间需要4分钟。
在Linux中,使用`cgroup`机制可以对进程的资源使用进行限制。例如,`cgroup`本身不直接提供`read_iops`这样的原生控制器(尽管在cgroup v1中存在)。但是,可以通过`blkio`子系统(在cgroup v1中)或更现代的`io`控制器(在cgroup v2中)对块设备I/O进行限制,包括限制读取操作的IOPS(每秒IO次数)。
若未对频繁的日志读取进程(如使用`tail -f`、grep日志、日志收集agent等)进行限制,可能会导致磁盘带宽被过度占用,影响关键服务的性能。以下是一些基于实际应用的可行方案:
确认使用 cgroup 版本并启用 io 控制器
现代发行版(如 CentOS 8+/RHEL 8+、Ubuntu 20.04+)默认启用 cgroup v2。需确认:
- 运行
mount | grep cgroup,若看到type cgroup2即为 v2; - cgroup v2 的
io控制器支持按设备设置io.max,其中可指定rps(read operations per second)——这正是你所需的read_iops限制; - 确保内核启用了
CONFIG_CGROUP_IO(主流发行版默认开启)。
使用 cgroup v2 设置 per-device 读 IOPS 上限
以限制进程对 /dev/sda 的读 IOPS 为 100 次/秒为例(需 root 权限):
- 创建控制组:
mkdir -p /sys/fs/cgroup/logreader; - 写入设备+限速规则(格式:
<major>:<minor> rps=<value>):echo "8:0 rps=100" > /sys/fs/cgroup/logreader/io.max(8:0是/dev/sda的主次设备号,用ls -l /dev/sda查看); - 将目标进程加入该组:
echo <PID> > /sys/fs/cgroup/logreader/cgroup.procs; - 验证:向该组写入任意值后,检查
cat /sys/fs/cgroup/logreader/io.stat中是否出现rqos相关统计,且读请求被节流。
对日志读取进程做自动化管控(推荐实践)
避免手动绑 PID,建议结合 systemd 或启动脚本实现持久化控制:
- 若用 systemd 启动日志工具(如 filebeat、fluent-bit),在 service 文件中添加:
IOReadBandwidthMax=/dev/sda 100(单位:IOPS,systemd 245+ 支持); - 或在启动前通过
cgexec(需安装libcgroup-tools):cgexec -g io:/logreader your-log-reader-command; - 注意:cgroup v2 要求进程及其所有子进程都在同一控制组内,否则子进程可能逃逸限速。
验证与调优要点
单纯设限不等于生效,需实测确认:
- 用
iostat -x 1观察r/s(read requests per second)是否稳定在设定值附近; - 用
dd if=/path/to/big.log bs=4k count=100000 | wc模拟突发读,看是否被平滑压制; - 注意:rps 限制是“设备级”而非“文件级”,若日志分散在多个磁盘,需分别配置;
- 若进程使用 direct I/O(如某些日志 agent 开启
O_DIRECT),部分内核版本下 rps 限速可能不生效,此时需改用bps(带宽)限制作为补充。
不复杂但容易忽略的是设备号匹配和 cgroup 版本一致性。只要路径、设备号、控制器启用三者到位,read_iops 级别的硬性限制就能可靠落地。

