MySQL在NVMe上未提速主因是innodb_io_capacity未实测调优:应以fio测得的稳定随机写IOPS×0.7~0.8设innodb_io_capacity,×1.5~2设innodb_io_capacity_max,同时关闭innodb_flush_neighbors、调高IO线程数至6~8、启用O_DIRECT及none调度器。

MySQL在NVMe盘上没变快,大概率是innodb_io_capacity还按HDD或普通SSD设的——NVMe的真实随机写IOPS远超传统配置逻辑,不实测、不调参,InnoDB根本“感觉不到”硬件有多快。
用fio实测你的NVMe真实随机写IOPS
别信厂商标称值,也别抄网上“设成4000”这种模糊建议。NVMe性能差异极大:消费级可能8万IOPS,企业级能到25万+,但实际数据库负载下的稳定值才是关键。
- 运行命令:
fio --name=randwrite --ioengine=libaio --rw=randwrite --bs=16k --iodepth=64 --runtime=60 --direct=1 --filename=/path/to/mysql/data/testfile - 重点看输出里的
iops字段(不是MB/s),取最后30秒稳定平均值 - 如果
/proc/diskstats中对应设备的%util == 100%且await > 5ms,说明当前IO已饱和,调参前先确认是不是真瓶颈
设innodb_io_capacity和innodb_io_capacity_max成对生效
这两个参数必须同时显式配置,缺一不可。InnoDB不会自动推导innodb_io_capacity_max的合理值,依赖默认行为在线上极危险。
-
innodb_io_capacity= 实测IOPS × 0.7~0.8(留余量防打满,例如实测18万 → 设126000) -
innodb_io_capacity_max=innodb_io_capacity× 1.5~2(例如126000 → 设189000~252000) - 设太高会导致
log file is full、Waiting for query cache lock等待飙升;设太低则Pages flushed曲线出现15分钟周期性毛刺
配套必须关掉innodb_flush_neighbors并调高IO线程数
NVMe没有寻道延迟,“邻近页刷新”是为HDD磁头优化的策略,在NVMe上只会制造无效IO,实测可稳提15%+吞吐。
-
innodb_flush_neighbors = 0(务必显式关闭) -
innodb_write_io_threads和innodb_read_io_threads各设为6~8(默认4,NVMe多核并发强,不压满就浪费) -
innodb_lru_scan_depth增至3072~4096(加快LRU链表扫描,避免缓存淘汰滞后)
确认底层IO路径没被OS调度器或文件系统拦腰截断
参数全对了但性能没起来?八成是IO被卡在Linux内核层。NVMe必须用none调度器,否则cfq或mq-deadline会引入排队抖动。
- 查当前调度器:
cat /sys/block/nvme0n1/queue/scheduler(把nvme0n1换成你的真实设备名) - 临时生效:
echo none > /sys/block/nvme0n1/queue/scheduler - 确认
innodb_flush_method = O_DIRECT(绕过OS page cache,让InnoDB直接感知真实IO延迟) - 文件系统挂载选项加
noatime,barrier=0,data=writeback(仅限数据库专用盘)
最易被忽略的一点:所有这些参数都依赖innodb_adaptive_flushing = ON才能动态响应负载变化。MySQL 5.6+默认开,但旧配置可能显式关掉了——上线前务必SHOW VARIABLES LIKE 'innodb_adaptive_flushing'确认。


















