SSD上MySQL写入慢主因是InnoDB刷盘参数配置不当,需实测SSD随机写IOPS(用fio),据此设innodb_io_capacity(实测×0.7~0.8)和innodb_io_capacity_max(前者×1.5~2),并调低innodb_max_dirty_pages_pct至25~40、开启innodb_adaptive_flushing,同时确保innodb_flush_method=O_DIRECT且NVMe/SATA调度器为none/noop。

SSD上MySQL写入慢,八成不是硬盘不行,而是innodb_io_capacity设得太保守,或者innodb_flush_log_at_trx_commit和sync_binlog组合没对齐硬件能力。直接调高参数不解决问题,得按SSD真实随机写IOPS来反推,再配合刷盘节奏控制。
查清你的SSD真实随机写IOPS
别信厂商标称值,也别沿用HDD时代的200或1000。实测才是唯一依据:
- 用
fio跑压测:fio --name=randwrite --ioengine=libaio --bs=16k --iodepth=64 --runtime=60 --filename=/path/to/mysql/data --direct=1 - 重点看
iops字段输出,取稳定值(不是峰值) - 消费级NVMe常见在8万–15万IOPS,企业级可到20万+;SATA SSD通常在2万–5万
- 如果
/proc/diskstats里对应设备的%util == 100%且await > 5ms,说明当前配置已压满磁盘,调参前先确认是不是IO真瓶颈
设置innodb_io_capacity与innodb_io_capacity_max
这两个值必须成对出现,且innodb_io_capacity_max不能为0或缺省——InnoDB会自动按2倍算,但不可控,线上严禁依赖。
-
innodb_io_capacity= 实测IOPS × 0.7~0.8(留余量),例如实测12万 → 设84000 -
innodb_io_capacity_max=innodb_io_capacity× 1.5~2,例如84000→ 设126000~168000 - 设太高会导致
log file is full、Waiting for query cache lock类等待飙升,本质是刷盘跟不上redo循环 - 设太低则脏页积压,
Pages flushed曲线会出现15分钟周期性毛刺(日志切换触发强制刷盘)
匹配刷盘节奏:innodb_max_dirty_pages_pct与innodb_adaptive_flushing
SSD不怕小写,怕的是“攒一堆再猛 flush”,这会让IO曲线剧烈抖动。要让刷盘更平滑:
-
innodb_max_dirty_pages_pct = 25~40(默认90太高,SSD下完全没必要留这么大缓冲) -
innodb_adaptive_flushing = ON(MySQL 5.6+默认开启,但务必确认没被显式关掉) - 禁用
innodb_adaptive_flushing_lwm(MySQL 8.0.23+已废弃,旧版本若设了要清空) - 观察
SHOW ENGINE INNODB STATUS\G里的Pages flushed是否平稳;若仍脉冲式上涨,说明innodb_io_capacity_max不够或innodb_write_io_threads不足
确认O_DIRECT与IO调度器是否生效
参数调对了,但底层被OS拦腰截断,一切白搭:
- 检查
innodb_flush_method = O_DIRECT(Linux下必须,否则OS page cache干扰InnoDB IO判断) - 查调度器:
cat /sys/block/nvme0n1/queue/scheduler(NVMe设备名替换成你的),应为[none];SATA SSD应为[noop] - 临时切调度器:
echo none > /sys/block/nvme0n1/queue/scheduler;永久生效需改/etc/default/grub加elevator=none - 容器或云主机环境无法改内核参数时,优先确认宿主机已配好,否则参数调再细也无效
最容易被忽略的一点:innodb_io_capacity不是IO加速器,它只是InnoDB内部调度刷盘任务的“节拍器”。如果%util已经100%,或者await持续高于10ms,说明磁盘本身卡死,此时所有参数调整都是徒劳——先停写、查硬件、看队列深度,再谈调优。


















