一、功能概述
·业务间 IO 相互干扰:单个容器打满磁盘带宽,导致共享存储上的其他业务出现 IO 抖动。
·额外写入开销:ext4 默认挂载参数会更新访问时间(atime),带来不必要的写入放大。
·高并发下系统调用开销大:传统 aio 接口在高并发场景下的系统调用开销过高,难以支撑低延迟需求。
TencentOS Server 4 基于 Linux 6.6 内核,默认为 NVMe 选用 mq-deadline 调度器,完整支持 cgroup v2 IO 带宽/IOPS 限制,并提供 io_uring 异步 IO 接口。通过合理调整 IO 调度器、文件系统挂载选项和 cgroup IO 限制,可以让关键业务在共享存储上获得稳定的 QoS。
二、注意事项
·IO 调优参数需结合实际业务负载进行测试验证。建议你使用 fio 进行基准测试后再调整生产参数。
·NVMe 设备推荐使用 none 调度器以获得最佳延迟,机械硬盘推荐 bfq 以获得公平调度。
·ext4 data=writeback 模式在系统崩溃时可能丢失最近写入的数据,数据库等强一致性业务应使用默认的 ordered 模式。
·cgroup io.max 限制只对设备繁忙时生效,设为 max 表示不限制对应维度。
·容器内执行 IO 调度器切换和 cgroup IO 限制需要特权模式或在宿主机操作,普通容器可能因 /sys 只读而失败。
四、IO 调度器
| 调度器 | 适用场景 | 说明 |
| mq-deadline | NVMe / SSD | 基于截止时间的多队列调度,默认选项 |
| none | NVMe(高性能) | 直通模式,无调度,适用于低延迟设备 |
| bfq | 机械硬盘 / 混合 | 公平队列调度,适合交互式场景 |
| kyber | NVMe | 自适应调度,适合高并发 |
五、cgroup v2 IO 控制接口
| 接口文件 | 取值范围 | 默认值 | 读写含义 |
| io.max | MAJ:MIN rbps=<N> wbps=<N> riops=<N> wiops=<N> | 无限制(max) | 读写:设置设备读写带宽和 IOPS 上限 |
| io.weight | default 1-10000 | default 100 | 读写:设置 IO 权重,仅在设备繁忙时生效 |
| io.stat | 只读 | — | 读:查看当前 IO 统计(字节/IOPS) |
六、文件系统挂载选项(ext4)
| 参数 | 取值 | 默认值 | 说明 |
| noatime | 挂载选项 | 未启用 | 不更新访问时间,减少写入 |
| data=writeback | ordered/writeback/journal | ordered | 写回模式,性能优先。注意:系统崩溃时可能导致数据丢失,仅适用于可容忍数据丢失的场景。 |
| discard | 挂载选项 | 未启用 | 启用 TRIM(SSD/NVMe) |
七、关键 sysctl 参数
注意:警告:
注意:部分 sysctl 参数名称可能因内核版本不同存在差异,可通过 sysctl -a 查看当前系统可用参数。
| 参数 | 推荐值 | 默认值 | 说明 |
| vm.dirty_ratio | 10-20 | 20 | 脏页占比阈值,触发同步写入 |
| vm.dirty_background_ratio | 5-10 | 10 | 脏页占比阈值,触发异步写入 |
| vm.dirty_expire_centisecs | 3000 | 3000 | 脏页过期时间(单位:1/100 秒,3000=30秒) |
| vm.swappiness | 10-20 | 60 | swap 倾向度,值越低越倾向于回收内存页 |
| vm.dirty_writeback_centisecs | 500 | 500 | 脏页回写间隔(单位:1/100 秒,500=5秒) |
九、查看与切换 IO 调度器
请你根据设备类型选择目标调度器:NVMe/SSD 设备推荐 none(低延迟)或保持 mq-deadline(默认均衡);机械硬盘推荐 bfq(公平调度)。
查看系统中的块设备,确定设备名(NVMe 设备显示为 nvme0n1,virtio 虚拟磁盘显示为 vda):
lsblk
输出示例:
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINTSvda 253:0 0 50G 0 disk└─vda1 253:1 0 50G 0 part /
查看当前调度器(输出中带方括号的调度器为当前生效项,其余为系统支持的可用调度器不同设备和内核版本支持的调度器列表可能不同):
# 查看当前调度器(将 <设备名> 替换为上一步获取的实际设备名)# 输出中方括号 [ ] 内为当前生效的调度器,其余为系统支持的可用调度器# 不同设备和内核版本支持的调度器列表可能不同cat /sys/block/<设备名>/queue/scheduler
输出示例:
none [mq-deadline] kyber bfq
切换调度器:
注意:警告:
注意:切换 IO 调度器会立即生效,可能影响设备的 IO 延迟和吞吐特性。建议在维护窗口或非生产环境操作,并提前用 fio 等工具验证不同调度器对业务负载的影响。NVMe 设备推荐使用 none 调度器以获得最佳延迟,机械硬盘推荐 bfq 以获得公平调度。
echo none > /sys/block/<设备名>/queue/scheduler
验证切换结果:
cat /sys/block/<设备名>/queue/scheduler
输出示例:
none [none] kyber bfq
十、持久化 IO 调度器(udev 规则)
创建 udev 规则(写文件命令,执行成功时无输出):
echo 'ACTION=="add|change", KERNEL=="nvme[0-9]*n[0-9]*", ATTR{queue/scheduler}="none"' > /etc/udev/rules.d/60-io-scheduler.rules
立即应用规则:
注意:警告:
注意:该命令会对系统中所有设备触发 udev change 事件,可能引发短暂的 I/O 抖动,请你先在测试环境验证影响后再执行。
udevadm trigger –type=devices –action=change
十一、限制容器 IO 带宽
注意:说明:
注意:以下操作需要 root 权限,且系统运行在 cgroup v2(unified)模式下。TencentOS Server 4 默认使用 cgroup v2。
获取目标设备主从设备号:
lsblk -o NAME,MAJ:MIN
输出示例:
NAME MAJ:MINnvme0n1 259:0
创建 IO 受限的 cgroup,设置读写带宽限制(示例:10MB/s)和 IOPS 限制(示例:500)。将 259:0 替换为上一步获取的实际设备号,写操作执行成功时均无输出:
注意:警告:
mkdir /sys/fs/cgroup/io_limitedecho "259:0 rbps=10485760 wbps=10485760 riops=500 wiops=500" > /sys/fs/cgroup/io_limited/io.maxecho $PID > /sys/fs/cgroup/io_limited/cgroup.procs
写入后可执行以下命令确认限制已生效:
cat /sys/fs/cgroup/io_limited/io.max
输出示例:
259:0 rbps=10485760 wbps=10485760 riops=500 wiops=500
十二、文件系统挂载优化
重新挂载根文件系统:
注意:警告:
注意:noatime 会关闭访问时间记录,依赖 atime 的应用(如 tmpwatch、部分备份和监控工具)可能受影响。
mount -o remount,noatime,nodiratime /
对新分区格式化并挂载(ext4 + writeback 模式,仅限可容忍数据丢失场景)。格式化和挂载命令执行成功时无输出:
注意:警告:
mkfs.ext4 -O has_journal /dev/vdb1mount -o noatime,data=writeback,discard /dev/vdb1 /data
挂载完成后,可执行以下命令确认挂载参数已生效:
mount | grep /data
输出示例:
/dev/vdb1 on /data type ext4 (rw,noatime,data=writeback,discard)
十三、io_uring 支持检查
检查内核 io_uring 支持:
grep CONFIG_IO_URING=y /boot/config-$(uname -r)
输出示例:
CONFIG_IO_URING=y
查看 io_uring 相关 sysctl。kernel.io_uring_disabled 控制 io_uring 可用性:0=全部启用,1=仅特权用户可用,2=完全禁用:
sysctl -a | grep io_uring
输出示例:
kernel.io_uring_disabled = 0
修改 io_uring 可用性:
注意:警告:
注意:kernel.io_uring_disabled 修改后立即生效:
注意:请勿在生产环境随意调整,确需调整时先在测试环境验证影响。
临时修改(运行时生效,重启后失效):
sysctl -w kernel.io_uring_disabled=1
输出示例:
kernel.io_uring_disabled = 1
持久化修改:
echo "kernel.io_uring_disabled = 1" > /etc/sysctl.d/99-io-uring.confsysctl –system
输出示例(sysctl –system 会列出所加载的配置文件及参数值):
* Applying /etc/sysctl.d/99-io-uring.conf …kernel.io_uring_disabled = 1
十四、性能基准测试(fio)
fio 默认未安装,使用前需先安装:
# 安装 fiodnf install -y fio
注意:说明:
顺序读写测试:
fio –name=seqread –rw=read –bs=1M –size=1G –numjobs=1 –time_based –runtime=60 –group_reporting
输出示例:
seqread: (g=0): rw=read, bs=(R) 1024KiB-1024KiB, (W) 1024KiB-1024KiB, (T) 1024KiB-1024KiB, io=60.0GiB…read: IOPS=18.2k, BW=18.2GiB/s (19.6GB/s)(60.0GiB/60001msec)
随机读写测试:
fio –name=randrw –rw=randrw –bs=4k –size=1G –numjobs=4 –time_based –runtime=60 –group_reporting –rwmixread=70
输出示例:
randrw: (g=0): rw=randrw, bs=(R) 4096B-4096B, (W) 4096B-4096B, (T) 4096B-4096B, io=3364MiB…read: IOPS=71.8k, BW=280MiB/s (294MB/s)(42.0GiB/60001msec)write: IOPS=30.7k, BW=120MiB/s (126MB/s)(18.0GiB/60001msec)
输出中的 read: IOPS=xxx 和 write: IOPS=xxx 为关键指标行,可据此对比调优前后效果。
十六、Q1:切换 IO 调度器后提示 "Operation not permitted"
原因:非 root 用户或设备不支持动态切换调度器。
解决:切换到 root 权限后重试。
# 1. 确认 root 权限sudo -i# 2. 查看设备支持的调度器cat /sys/block/<设备名>/queue/scheduler# 3. 若目标调度器不在列表中,说明内核未编译该调度器
十七、Q2:调整 nr_requests 后 IO 性能未提升
原因:nr_requests 仅影响块层队列深度,对 NVMe 等高速设备效果有限。瓶颈可能在设备本身或文件系统层。
解决:用 fio 做基准测试对比,同时检查文件系统挂载参数和设备队列深度:
# 查看设备队列深度cat /sys/block/<设备名>/device/queue_depth# 检查文件系统挂载参数mount | grep <设备名>
十八、Q3:cgroup io.max 限制不生效
原因:cgroup v2 的 io 控制器仅在设备繁忙时生效,或系统未启用 cgroup v2。
解决:确认 cgroup v2 已启用,并检查限制值是否已正确写入:
# 1. 确认 cgroup v2 已启用mount | grep cgroup2# 2. 确认 io 控制器可用cat /sys/fs/cgroup/cgroup.controllers | grep io# 3. 确认限制值已写入cat /sys/fs/cgroup/<cgroup_name>/io.max
十九、Q4:ext4 data=writeback 模式导致数据丢失
原因:writeback 模式下文件系统在数据写入缓存后即视为完成,不强制保证数据落盘顺序。当系统异常崩溃时,缓存中尚未持久化到磁盘的数据将丢失,存在数据一致性风险。
解决:数据库等对数据一致性要求较高的业务,应保持默认的 ordered 模式,避免切换为 writeback 模式。
20、Q5:容器内无法切换 IO 调度器
原因:容器环境中 /sys 目录通常以只读方式挂载,容器内进程无权限修改块设备调度策略等内核参数。
解决:请你在宿主机上执行相关操作,或使用特权容器(–privileged)启动以获取 /sys 的写入权限。