直接改innodb_io_capacity不起作用,因其仅为后台i/o节奏的“节拍器”,需同步调整innodb_io_capacity_max、innodb_flush_neighbors、innodb_read_io_threads/innodb_write_io_threads、innodb_lru_scan_depth四参数,并关闭linux i/o调度器。

为什么直接改 innodb_io_capacity 不起作用
单独调高 innodb_io_capacity 基本没用,它只是后台I/O节奏的“节拍器”,不是带宽开关。InnoDB用它控制每秒刷多少脏页、合并多少插入缓冲、扫描多深的LRU链表——值设得再大,如果配套参数没跟上,IO线程卡住、邻近页刷新还在瞎忙、调度器还在做无用功,SSD的真实IOPS就释放不出来。
- 常见错误现象:
Innodb_buffer_pool_pages_free = 0但Innodb_buffer_pool_wait_free持续非零,说明刷脏页跟不上写入速度 - SSD上仍看到大量
os_log_pending_writes或innodb_data_pending_writes,大概率是innodb_io_capacity_max太低或线程数不足 - 用
fio测出随机写有12万 IOPS,但MySQL实际IO吞吐卡在2万左右,八成是Linux I/O调度器没关
必须同步调整的4个关键参数
SSD不是“更快的HDD”,它是另一套IO逻辑。以下4项不一起改,innodb_io_capacity 就是纸上谈兵:
-
innodb_io_capacity_max:设为innodb_io_capacity的2–2.5倍(例如前者设9000,后者至少18000),否则突发写入时直接被限死 -
innodb_flush_neighbors:务必设为0。HDD时代为减少寻道合并邻近页,SSD上这操作纯属制造无效IO -
innodb_read_io_threads和innodb_write_io_threads:各设为4~8(默认都是4)。SSD并发能力强,线程太少会饿着IO队列 -
innodb_lru_scan_depth:从默认1024提到2048或4096。SSD响应快,可以更激进地扫描LRU链表,避免缓存淘汰滞后
如何测出你SSD的真实IOPS值
别信厂商标称值,也别用 dd 测顺序读写。数据库真实压力是小块、随机、高队列深度的写入:
- 用这个命令实测:
fio --name=randwrite --ioengine=libaio --rw=randwrite --bs=4k --numjobs=1 --iodepth=64 --runtime=60 --time_based --direct=1 --filename=/path/to/ssd/testfile - 重点看输出里的
iops行(不是bw),取最后30秒稳定值 - 生产建议值 = 实测IOPS × 0.6~0.8(写密集型可到0.9),例如实测115000 → 设
innodb_io_capacity = 85000 - 注意:测试文件要大于Buffer Pool,且避开系统盘和日志盘,否则测的是瓶颈而非SSD本身
容易被忽略的系统层开关
MySQL参数调得再准,底层OS拦着,照样白搭:
- 检查当前I/O调度器:
cat /sys/block/nvme0n1/queue/scheduler(把nvme0n1换成你的设备名) - 临时关闭:
echo none > /sys/block/nvme0n1/queue/scheduler(NVMe)或echo noop > /sys/block/sda/queue/scheduler(SATA SSD) - 永久生效需改
/etc/default/grub,在GRUB_CMDLINE_LINUX加elevator=none,再update-grub && reboot - 云主机或容器环境可能无法直接改,得确认宿主机是否已配好;没权限时,至少确保没启用
cfq或deadline
真正卡住SSD性能的,往往不是MySQL配置本身,而是调度器、邻近页刷新、IO线程数这些“默认开着但不该开”的东西。调参前先验证实测IOPS,调完后盯紧 Innodb_buffer_pool_wait_free 和 os_log_pending_writes 这两个状态变量——它们比任何监控图表都诚实。











