八成是磁盘响应跟不上fsync(3),需用strace盯worker线程、iostat/iotop验证io瓶颈,并结合innodb日志状态与变量确认刷盘滞后。

strace盯住mysqld线程看是否卡在fsync(3)
事务提交慢,八成不是SQL写得差,而是卡在fsync(3)系统调用上。别猜,直接抓证据:strace -p $(pgrep mysqld | head -1) -e trace=fsync,挑一个状态为Updating或Writing to net的线程盯几秒。如果看到fsync(3)调用后长时间没返回(比如 >50ms),基本坐实是磁盘响应跟不上。
注意:别用strace -f全进程跟踪——开销太大,可能干扰本身;也别只盯主线程,要找正在执行COMMIT的worker线程(ps -eo pid,comm,tid,state,wchan,lwp,pcpu,iowait里找iowait高的LWP)。
iostat和iotop交叉验证IO是否真饱和
iostat -x 1输出里只盯两个数字:%util持续 >80% 且 await >10ms(SSD)或 >50ms(HDD),同时出现就是硬瓶颈。单看rkB/s或wkB/s没意义——MySQL刷redo是密集小IO(4KB–16KB),IOPS比吞吐更关键。
接着用iotop -oP确认是不是mysqld在刷盘:WRITE列占比超60%,且IO>列数值频繁跳动,说明压力确实来自MySQL。云盘场景(如ESSD、gp3)还要加一句:iotop -p $(pgrep mysqld)看实际发出的写请求大小和频率,再查控制台IOPS配额是否耗尽。
- 机械盘慎用
innodb_flush_method=O_DIRECT,可能反而更慢 - RAID卡缓存失效时,write back会自动降级为write through,日志写变同步阻塞
- redo日志文件(
ib_logfile*)所在磁盘必须单独监控,别和data目录混在一起看
查InnoDB状态和变量确认日志刷盘滞后
SHOW ENGINE INNODB STATUS\G里的LOG段是核心证据:Log sequence number和Log flushed up to差距持续拉大(比如超过200MB),说明log buffer写入速度远超刷盘能力;Last checkpoint at长期不动,也佐证checkpoint被拖住。
再查状态变量:Innodb_os_log_pending_fsyncs非零且持续上升,Innodb_log_writes随TPS线性飙升,Innodb_buffer_pool_hit_rate低于99%——最后这个值低,说明热数据根本没留在内存,先优化查询和buffer pool大小,别急着调IO参数。
-
Innodb_log_file_size太小(如默认48M)会导致高频checkpoint,表现为周期性毛刺(每1–2分钟卡一下) - 调整它必须停库:
SET GLOBAL innodb_fast_shutdown = 0→ 关mysqld → 删除ib_logfile0/ib_logfile1→ 改配置 → 启动 -
innodb_log_files_in_group只影响文件个数,总容量由innodb_log_file_size × innodb_log_files_in_group决定
autocommit关了会制造“假慢”
很多ORM或连接池默认关闭autocommit,结果所有DML堆在一个事务里,最后COMMIT才爆发式刷盘——这不是慢,是压根没提交。连上就查:SELECT @@autocommit;,生产环境必须为1。
如果业务真需要长事务,至少确保innodb_flush_log_at_trx_commit=1搭配sync_binlog=1时,别让单条INSERT配一个COMMIT——批量写+合理分批才是解法。否则调参只是掩耳盗铃。
真正棘手的是双刷盘叠加:innodb_flush_log_at_trx_commit=1 + sync_binlog=1,每次COMMIT触发两次fsync,哪怕换NVMe也照样卡。这时候看证据比拍脑袋调参重要得多。











