innodb_io_capacity 应根据磁盘实际稳定随机写iops的70%设定:nvme ssd设2000–4000,sata ssd设800–1600,企业级sas hdd不超200;innodb_io_capacity_max设为前者的1.5–2倍,需结合trim启用、buffer pool大小及ssd健康度动态调整。

innodb_io_capacity 值设多少才不浪费磁盘又不卡住刷脏?
这个值不是越大越好,也不是照搬磁盘 IOPS 算出来的数字就对。它本质是告诉 InnoDB:「你每秒最多可以发起多少次 IO 请求来刷脏页或做预读」。设高了,InnoDB 会猛发 IO,但若底层磁盘跟不上(比如 SATA SSD 实际随机写 IOPS 只有 2k,你设成 8000),反而引发队列堆积、io_wait 升高、响应延迟跳升;设低了,刷脏跟不上修改速度,Dirty pages 持续堆积,最终触发 adaptive hash index 降级或强制同步刷盘,一样卡。
实操建议:
- 用
iostat -x 1观察业务高峰期的%util和await—— 如果%util长期 > 80% 或await> 10ms,说明磁盘已饱和,innodb_io_capacity应 ≤ 当前实际稳定随机写 IOPS 的 70% - NVMe SSD(如 Intel P5800X)可设 2000–4000;SATA SSD(如 Samsung 870 EVO)建议 800–1600;企业级 SAS HDD 通常不超 200
- 别直接抄厂商标称「最大 IOPS」——那是 4K 随机读、队列深度 32 下测的,mysql 刷脏是混合读写、队列深度低,真实可用值打 4–6 折更稳妥
innodb_io_capacity_max 是用来兜底还是压测用?
它是 innodb_io_capacity 的弹性上限,只在以下两个场景被激活:后台线程刷脏压力大时临时上浮、以及崩溃恢复后加速重放 redo。它不是「日常能一直跑的值」,设太高会导致突发 IO 打满磁盘,影响主库响应。
实操建议:
- 常规部署下,设为
innodb_io_capacity的 2× 是安全的(例如前者 1200,后者 2400) - 如果实例混跑其他服务(比如同机器跑 redis 或备份进程),必须再打个折,避免 IO 抢占 —— 此时
innodb_io_capacity_max设成 1.5× 更稳 - 注意:MySQL 5.7+ 中,当
innodb_adaptive_flushing开启时,该值会影响自适应刷脏算法的激进程度;关掉它的话,这个参数几乎不生效
SSD 寿命和 TRIM 对这两个参数的影响被严重低估
很多 dba 调高 innodb_io_capacity 后发现写放大暴增、延迟毛刺变多,却没意识到:SSD 在长期使用后,空闲块回收变慢,写入延迟不再稳定。此时即使磁盘标称 IOPS 没变,实际可用吞吐已下降。
实操建议:
- 确认 SSD 是否启用 TRIM:
lsblk -D查看Disc-GRAN和Disc-MAX是否非零;没启用就加discard=on到挂载选项,并重启 MySQL(否则后台刷脏持续写入已标记删除的块) - 定期运行
fstrim(比如每天一次),否则 SSD 内部 GC 压力增大,await会缓慢爬升,原来合适的innodb_io_capacity就变得偏高 - 监控
/proc/diskstats中对应设备的ms_ios字段趋势 —— 若它随时间单边上涨,哪怕%util不高,也说明 SSD 内部延迟恶化,该调低参数了
为什么 buffer pool 大小会反向影响这两个参数的效果?
很多人调完参数发现没改善,其实是 buffer pool 设置过大,导致脏页生成速度远超 IO 能力。这时再怎么调高 innodb_io_capacity,也只是让刷脏更“努力地失败”。
实操建议:
- 检查
Innodb_buffer_pool_pages_dirty/Innodb_buffer_pool_pages_total比值 —— 持续 > 15% 说明刷脏追不上,优先考虑缩小innodb_buffer_pool_size(比如从 75% 降到 60%),而不是硬抬 IO 参数 - 高并发 OLTP 场景下,buffer pool 过大会增加 page cleaner 线程锁竞争,反而降低刷脏效率;此时适当降低 buffer pool,配合合理 IO 参数,整体吞吐可能更高
- 如果用了
innodb_buffer_pool_instances > 1,确保实例数与 CPU 核心数匹配(一般设为 8 或 16),否则多个 cleaner 线程争同一把锁,IO 参数再准也没用
真正难的不是算出一个数字,而是持续观察 Dirty pages 波动、io_wait 分布、SSD 内部健康度三者之间的咬合关系。参数调得再准,硬盘悄悄老化了,也会失效。