磁盘io瓶颈需通过iostat -x 1查%util(>80%危险)和await(>10ms异常),结合iotop确认mysqld刷盘、检查磁盘类型与iops配额、避免raid缓存降级,并合理配置innodb_flush_log_at_trx_commit、sync_binlog、innodb_log_file_size及刷脏页参数。

磁盘IO是否真成了瓶颈
直接看 iostat -x 1,重点盯 %util(持续 >80% 就危险)和 await(>10ms 表示单次IO等待过长)。别只看吞吐量,MySQL 写入慢常是随机小IO卡住,不是带宽不够。
常见错误现象:监控显示CPU、内存都宽松,但 INSERT 延迟飙升,SHOW PROCESSLIST 里一堆 Writing to net 或 Updating 卡住——这往往是磁盘响应跟不上,不是SQL本身慢。
- 用
iotop -oP确认是不是mysqld进程在大量刷盘(特别是innodb_log_file_size小 + 高并发写时,log buffer频繁flush) - 检查磁盘类型:机械盘(HDD)跑
innodb_flush_method=O_DIRECT可能更差,SSD才真正受益;云盘注意IOPS配额是否被占满(比如阿里云ESSD的burst模式耗尽后降速) - 避免误判:RAID卡缓存未启用或电池失效时,
write back会自动降级为write through,导致日志写变同步阻塞
innodb_flush_log_at_trx_commit 和 sync_binlog 怎么设
这两个配置联手决定“事务提交”是否真落到磁盘。设错一个,要么丢数据,要么写入直接掉一倍以上速度。
使用场景:业务允许最多丢失1秒事务(如日志类、埋点),可调松;金融/订单类必须严格持久化。
-
innodb_flush_log_at_trx_commit = 1:每次事务都fsyncredo log,最安全,但磁盘压力最大 -
= 2:写入 OS cache 后就返回,依赖 OS 每秒刷盘,崩溃可能丢1秒数据;实测写入吞吐常提升3–5倍 -
sync_binlog = 1要求 binlog 也同步刷盘;若设为 0 或大于1,主从一致性风险上升,且可能掩盖真实IO压力(binlog暂存在page cache里不显形) - 二者必须协同:比如
innodb_flush_log_at_trx_commit=2但sync_binlog=1,会导致事务提交时仍被binlog的fsync卡住
redo log 文件大小和循环写是否拖慢刷新
太小的 innodb_log_file_size 会让 checkpoint 过于频繁,把本该后台做的刷脏页动作推到前台事务里,表现为“突然卡一下”。
错误现象:慢查询日志里没有慢SQL,但 INSERT 响应时间呈周期性毛刺(比如每2分钟一次明显延迟),SHOW ENGINE INNODB STATUS 中 LOG 部分显示 Log sequence number 和 Last checkpoint at 差距极小。
- 计算建议值:
innodb_log_file_size至少覆盖 1 小时的写入量(按Innodb_os_log_written/ 3600 推算),常见设置为 1G–4G,而非默认的 48M - 调整需停库:先
SET GLOBAL innodb_fast_shutdown = 0,再关mysqld,删旧log文件,改配置,重启 - 云环境注意:某些托管数据库(如AWS RDS)不允许直接调这个参数,得通过参数组修改并触发重启
刷脏页是否被低优先级任务卡住
当 buffer pool 里脏页太多、又没足够空闲线程来刷,新写入就得等——这时你看到的“写入慢”,其实是前台事务在等后台刷页完成。
关键指标看 SHOW GLOBAL STATUS LIKE 'Innodb_buffer_pool_pages_dirty' 和 Innodb_page_cleaner_waits(MariaDB/8.0+有,表示刷页线程忙不过来)。
- 检查
innodb_io_capacity是否严重低估磁盘能力(SSD建议设 2000+,HDD 200–500),它控制刷页线程的“努力程度” -
innodb_max_dirty_pages_pct设太高(如90%)会导致脏页堆积,建议 75–85;设太低(如50%)又让刷页过于激进,抢占IO资源 - 避免和备份冲突:
mysqldump --single-transaction本身不锁表,但若同时开启innodb_file_per_table=OFF,大表导出可能触发全表扫描+大量脏页生成,间接拖慢写入
最易被忽略的是:磁盘队列深度(avgqu-sz)长期 >1,说明IO请求已在内核队列排队,此时调任何MySQL参数都只是隔靴搔痒——得先解决底层存储供给问题。











