未提交事务不写入binlog但阻塞binlog cache释放;其binlog event滞留内存或临时文件,不落盘、不可见、不复制,且cache不自动清理,长事务会导致binlog_cache_disk_use飙升并拖慢io。

未提交事务不会写入Binlog,但会阻塞Binlog cache释放
很多人误以为“未提交事务的变更会被暂存进binlog”,这是错的。MySQL严格遵循两阶段提交(2PC)协议:只有事务真正执行COMMIT后,对应的binlog event才会从会话私有的binlog_cache刷出、落盘、并标记为可被从库消费。未提交事务的binlog event始终卡在内存(或溢出到磁盘临时文件),既不写入binlog文件,也不参与复制——所以你用mysqlbinlog查不到它,SHOW BINLOG EVENTS也看不到它。
但问题在于:binlog_cache是每个连接独占的,且**不会因为事务长时间未提交而自动清理或复用**。只要事务开着,这块内存(或磁盘临时文件)就一直被占用。当大量长事务并发存在时,Binlog_cache_disk_use指标会飙升,说明频繁触发缓存溢出;更严重的是,如果某个大事务本身产生超大变更(比如UPDATE百万行),它可能反复撑爆binlog_cache_size,导致持续写临时文件,最终拖慢整个实例的IO吞吐。
如何监控事务是否“活着但没提交”
关键不是看binlog堆积量,而是看事务本身是否异常存活。以下命令必须组合使用:
-
SELECT * FROM INFORMATION_SCHEMA.INNODB_TRX WHERE trx_state = 'RUNNING' AND TIME_TO_SEC(TIMEDIFF(NOW(), trx_started)) > 60:查运行超1分钟的活跃事务,重点关注trx_started和trx_mysql_thread_id -
SELECT * FROM INFORMATION_SCHEMA.PROCESSLIST WHERE ID IN (SELECT trx_mysql_thread_id FROM INFORMATION_SCHEMA.INNODB_TRX WHERE trx_state = 'RUNNING' AND TIME_TO_SEC(TIMEDIFF(NOW(), trx_started)) > 60):关联查出对应线程的SQL、用户、主机、状态(如Sleep或Query) -
SHOW ENGINE INNODB STATUS\G:在输出的TRANSACTIONS段里,找lock struct(s)数量多、ROLLING BACK或LOCK WAIT状态的事务,它们往往是阻塞源
注意:INFORMATION_SCHEMA.INNODB_TRX里的trx_state为RUNNING,不代表事务正在执行SQL——它只表示事务未提交,哪怕线程早已Sleep在那,也会一直挂着。
为什么waiting for handler commit是关键信号
这个状态不是锁等待,也不是IO等待,而是存储引擎层在等binlog写入完成。当一个事务准备提交时,InnoDB先写redo log,再通知server层写binlog;而server层必须把当前事务的全部binlog event从cache刷到磁盘(受sync_binlog控制),才能返回成功。如果此时有另一个大事务正卡在刷binlog cache(比如写了800MB还在往临时文件写),所有后续事务的COMMIT都会卡在waiting for handler commit。
排查时直接查:
SELECT STATE, INFO FROM INFORMATION_SCHEMA.PROCESSLIST WHERE STATE = 'waiting for handler commit'- 对比这些线程的
TIME列,如果远大于正常提交耗时(几毫秒),基本可断定上游有大事务霸占了binlog写入通道 - 立刻去
INNODB_TRX里找trx_started最早的那个事务,大概率就是根因
别只盯着binlog_size,要看Binlog_cache_disk_use
阿里云RDS控制台显示的binlog_size是已落盘的binlog文件总大小,它反映的是“已提交事务的历史总量”,对诊断长事务毫无价值。真正该盯的是性能状态变量:
-
SHOW GLOBAL STATUS LIKE 'Binlog_cache%',重点关注两个值:
–Binlog_cache_use:总使用次数
–Binlog_cache_disk_use:被迫写磁盘临时文件的次数 - 如果
Binlog_cache_disk_use / Binlog_cache_use > 0.1(即10%以上事务都溢出到磁盘),说明binlog_cache_size设得太小,或业务存在大量大事务 -
max_binlog_cache_size设得过大会掩盖问题(比如设成4GB),但设得太小又会导致大事务直接报ERROR 1197 (HY000): Multi-statement transaction required more than 'max_binlog_cache_size' bytes of storage,需权衡
最危险的情况是:Binlog_cache_disk_use持续上涨,但binlog_size增长缓慢——这说明大量事务卡在“未提交”状态,binlog cache被占满却无法释放,新事务连cache都分不到,只能排队等。











