事务提交慢八成是卡在fsync上,需用strace盯mysqld线程是否长时间停在fsync(3),结合show engine innodb status中log sequence number与log flushed up to差距拉大、innodb_os_log_pending_fsyncs非零持续上升、iostat的%util>80%且await>10ms、iotop确认mysqld大量刷盘等多维度证据综合判定。

事务提交突然变慢,八成不是SQL写得差,而是卡在fsync上——尤其是redo log或binlog的磁盘刷盘环节。
怎么确认是fsync卡住而不是SQL执行慢
别急着改配置,先抓证据。MySQL事务提交慢的本质,常是innodb_flush_log_at_trx_commit=1(默认值)导致每次COMMIT都调用fsync(3),而磁盘响应不过来。
- 用
strace -p $(pgrep mysqld | head -1) -e trace=fsync盯一个卡住的线程,看它是否长时间停在fsync(3)调用上 - 查
SHOW ENGINE INNODB STATUS\G里的LOG段:Log sequence number和Log flushed up to差距持续拉大,说明日志刷盘跟不上写入速度 - 监控
Innodb_os_log_pending_fsyncs状态变量,非零且持续上升就是铁证
iostat和iotop怎么看才算真IO瓶颈
只看吞吐量会误判。MySQL写入慢多是随机小IO拖垮,不是带宽不够。
-
iostat -x 1重点盯两个指标:%util > 80%(设备饱和)、await > 10ms(单次IO等待过长),若两者同时出现且持续,基本坐实磁盘瓶颈 -
iotop -oP确认是不是mysqld进程在大量刷盘——尤其注意WRITE列里mysqld的IO占比是否主导 - 云盘场景(如阿里云ESSD、AWS gp3)必须查IOPS配额是否耗尽;
iotop -p $(pgrep mysqld)还能看到实际发出的写请求大小,小块写(4KB–16KB)密集时,IOPS比吞吐更关键
innodb_log_file_size太小也会拖慢COMMIT
日志文件小,InnoDB被迫高频checkpoint,把本该后台做的刷脏页动作推到前台事务里,表现为“每批提交突然卡一下”。
- 估算:按峰值写入量算,至少容纳1–2分钟的
Innodb_os_log_written增速(单位字节/秒) - 不能在线改:必须停库 → 删除
ib_logfile0和ib_logfile1→ 修改配置 → 重启。否则启动失败报InnoDB: Error: log file ./ib_logfile0 is of different size -
innodb_log_files_in_group只影响文件个数,不改变总容量;真正起作用的是innodb_log_file_size × innodb_log_files_in_group
autocommit关了会导致“假慢”
很多ORM或连接池默认关闭autocommit,结果所有DML都堆在一个事务里,最后COMMIT才爆发式刷盘——这不是慢,是压根没提交。
- 连上就查:
SELECT @@autocommit;,生产环境应为1 - Python项目检查是否调用了
conn.autocommit(False)或conn.begin() - 连接池场景下最容易被忽略:一次请求忘了
COMMIT或ROLLBACK,下次取到该连接的应用一执行UPDATE就卡住
真正容易被忽略的是:事务提交慢这件事,往往发生在你没动任何SQL、也没加新业务的时候——它藏在日志刷盘路径、云盘IOPS配额、连接池会话复用这些“看不见”的地方。盯着fsync看,比优化索引更可能立刻见效。











