上一篇说到针对数据库在CPU/内存和Linux下的性能调优,今天我们来说说针对存储方面的一些性能优化,毕竟它也是服务器里非常重要的一部分。
这篇文章把 Linux I/O 优化拆成 8 个可落地的步骤,每一步都给出判断依据 + 具体操作命令。读完即可上手,改完记得用 fio 做对比验证。
适用场景:单台或少量 NVMe/SSD 服务器;Linux 内核版本建议 ≥ 3.19(blk-mq 默认开启),≥ 5.10 可进一步使用 io_uring。
01 选择高效的 I/O 调度器
I/O 调度器决定请求如何排队、合并和发送给硬件,选错调度器可能让高性能 NVMe 盘“有力使不出”。
| | |
|---|
| deadline | NVMe 本身并发能力强,过多调度反而增加延迟;deadline 对顺序 I/O 友好 |
| deadline | |
| deadline | |
查看当前调度器:
cat /sys/block/nvme0n1/queue/scheduler
设置为 deadline:
echo deadline | sudo tee /sys/block/nvme0n1/queue/scheduler
持久化建议:把上述命令写入 /etc/rc.local(需先给执行权限)或 udev 规则,避免重启后失效。
02 优化请求队列参数
队列深度和单次请求大小,直接影响并发吞吐。
2.1 调整单次 I/O 大小:max_sectors_kb
该参数限制单次 I/O 请求的最大扇区数。对 SSD 来说,适当调大可以减少请求拆分,提升吞吐。
echo 512 | sudo tee /sys/block/nvme0n1/queue/max_sectors_kb
2.2 调整队列深度:nr_requests
默认 128,对高并发场景可能不够。可尝试提高到 256~512,但过高会增加延迟,需要实测。
echo 256 | sudo tee /sys/block/nvme0n1/queue/nr_requests
注意:调优参数不是越大越好。建议先用 fio 测试不同数值下的 IOPS 和延迟,找到最佳点。
03 启用多队列架构(blk-mq)
传统单队列 Block Layer 在多核时代容易成为瓶颈。blk-mq(Multi-Queue Block Layer)让 I/O 请求绕过单一队列,直接分发到多核,是 NVMe 高性能的关键。
Linux 内核 ≥ 3.19 时,NVMe 驱动已经默认使用 blk-mq。如果你使用的是非常老的发行版,可以手动启用:
modprobe nvme blk_mq=1
验证是否启用:
ls /sys/block/nvme0n1/mq/ | head
现代系统建议:优先升级到内核 ≥ 5.x,并确保 NVMe 驱动使用原生多队列,无需额外配置。
04 使用异步 I/O:AIO / io_uring
同步 I/O 会让进程陷入等待,CPU 空转。异步 I/O 允许应用提交请求后继续做其他事,适合数据库、容器、日志等高频 I/O 场景。
- Linux 内核 < 5.10:
- Linux 内核 ≥ 5.10:推荐使用
io_uring,减少系统调用开销,性能更优
例如,Docker 在限制容器 I/O 带宽时,配合 AIO 能显著降低 I/O 等待:
docker run --device-read-bps=/dev/nvme0n1:100mb --device-write-bps=/dev/nvme0n1:100mb your_image
延伸阅读:关于 io_uring 的入门可以参考相关技术博客,后续我们也会单独写一篇 io_uring 实战。
05 优化挂载选项
挂载参数直接决定文件系统如何与硬件交互,两个常用选项:
noatime / relatime:discard:启用 TRIM,让 SSD 及时回收无效块,维持长期写入性能。
挂载示例:
sudo mount -o noatime,discard /dev/nvme0n1p1 /mnt/nvme
若需持久化,写入 /etc/fstab:
/dev/nvme0n1p1 /mnt/nvme ext4 noatime,discard,defaults 0 0
生产注意:修改 /etc/fstab 前务必备份,并用 mount -a 验证配置无语法错误,避免重启后无法挂载。
06 选择合适的文件系统
不同文件系统对存储设备的适配差异明显,常见选择如下:
选择时重点考虑:文件大小分布、并发访问模式、是否需要快照/校验。
07 调整内核内存参数
内存中的“脏数据”越多,写入磁盘的频率和策略就越影响 I/O 性能。
7.1 关键参数
vm.dirty_ratio:当脏页占系统内存达到该比例时,进程必须同步刷盘。默认值通常 20%,建议根据内存大小和 I/O 能力调整。vm.dirty_background_ratio:当脏页达到该比例时,后台刷盘线程开始工作。默认通常 10%。
7.2 临时生效
echo 20 | sudo tee /proc/sys/vm/dirty_ratio echo 10 | sudo tee /proc/sys/vm/dirty_background_ratio
7.3 持久化
echo "vm.dirty_ratio = 20" | sudo tee /etc/sysctl.d/99-custom.conf echo "vm.dirty_background_ratio = 10" | sudo tee -a /etc/sysctl.d/99-custom.conf sudo sysctl -p /etc/sysctl.d/99-custom.conf
避坑:不要把脏页比例设置过低(如 5%)。频繁刷盘会导致 I/O 抖动,反而拖慢整体性能。
08 预留未分区空间(Over-Provisioning)
固态硬盘依赖空闲块进行垃圾回收和坏块重映射。如果分区写满,性能会断崖式下降,且坏块风险增加。
建议:
- 在 SSD 上预留 10% ~ 20% 的未分区空间
- 或在文件系统层面保留足够余量,避免长期 90%+ 使用率
运维习惯:监控磁盘使用率时,把 80% 当作警戒线,85% 当作紧急处理线。
调优 checklist
每次做 I/O 调优,建议按下面顺序检查:
- 确认存储设备类型(NVMe / SSD / HDD)→ 选择调度器
- 调整队列参数(max_sectors_kb、nr_requests)
- 应用/容器是否使用异步 I/O(AIO / io_uring)
- 检查挂载选项(noatime / discard)
- 调整 vm.dirty_ratio 和 dirty_background_ratio
总结
Linux I/O 优化不是“调一个参数就能起飞”,而是调度器、队列、文件系统、挂载选项、内存策略、空间预留共同作用的结果。
建议:
如果这篇文章对你有帮助,欢迎转发给团队里的测试/运维同事。