innodb_io_capacity应设为SSD实测随机写IOPS的0.6~0.9倍(如115000 IOPS→85000),并同步调优innodb_io_capacity_max、innodb_flush_neighbors、IO线程数及LRU扫描深度,同时关闭Linux I/O调度器并优化系统级配置。

innodb_io_capacity设多少才不浪费SSD的IOPS
直接套用厂商标称值或HDD经验(比如设2000)会让SSD 80%以上的随机写能力闲置。它不是“上限”,而是InnoDB每秒计划刷脏页、合并插入缓冲等后台I/O任务的page数(16KB/page),值太低会导致Innodb_buffer_pool_wait_free持续非零、os_log_pending_writes堆积。
必须用fio实测你的SSD在数据库典型负载下的稳定随机写IOPS:
fio --name=randwrite --ioengine=libaio --rw=randwrite --bs=4k --numjobs=1 --iodepth=64 --runtime=60 --time_based --direct=1 --filename=/mnt/ssd/testfile- 重点看输出中
iops字段最后30秒的平均值,不是bw(带宽) - 生产取值 = 实测IOPS × 0.6~0.9:写密集型(如日志表)取0.8~0.9;读多写少可压到0.4~0.6
例如实测115000 IOPS → innodb_io_capacity = 85000 是合理起点。
为什么只改innodb_io_capacity基本没效果
这个参数单独调高就像给赛车换更快的油门踏板,但离合器打滑、变速箱卡顿、轮胎还装在拖拉机上——SSD的真实吞吐根本释放不出来。
必须同步调整这四个配套参数:
-
innodb_io_capacity_max设为innodb_io_capacity的2~2.5倍(如前者85000,后者至少170000),否则突发写入直接被硬限死 -
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链表,避免缓存淘汰滞后
Linux层I/O调度器是隐藏的性能杀手
MySQL参数调得再准,OS层拦着照样白搭。SSD不需要传统调度器做寻道优化,反而会被它拖慢。
检查当前调度器:cat /sys/block/nvme0n1/queue/scheduler(把nvme0n1换成你实际设备名)
正确做法是关闭调度器:
- 临时生效:
echo none > /sys/block/nvme0n1/queue/scheduler - 永久生效:在
/etc/default/grub中添加nvme_core.default_ps_max_latency_us=0,然后update-grub && reboot - 验证是否生效:重启后再次
cat该路径,输出应为[none]
如果这里还是[mq-deadline]或[kyber],上面所有MySQL参数调优都等于在高速公路上骑自行车。
容易被忽略的系统级内存与文件系统配置
SSD的高IOPS需要OS配合才能真正落到磁盘。两个关键点常被跳过:
-
vm.swappiness = 1:避免InnoDB buffer pool被swap出去,加到/etc/sysctl.conf并执行sysctl -p - 挂载选项必须含
noatime,nobarrier(XFS用nobarrier,ext4用barrier=0),且仅在有BBU/FBWC RAID卡或UPS时启用barrier=0;否则文件系统损坏风险陡增 - 文件系统选XFS(推荐)或较新内核的ext4,避免用ext3或NTFS
最麻烦的不是参数本身,而是它们之间的依赖关系:innodb_io_capacity调高了,但innodb_io_capacity_max没跟上,就卡在突发写;innodb_flush_neighbors=0关了,但OS调度器还在瞎忙,IO延迟照样上天。每个环节都得实测验证,不能只信配置清单。


















