binlog_cache_size写满后会立即卡住所有事务的COMMIT。MySQL为每个连接分配独立binlog cache,溢出时创建ML临时文件并持LOCK_log锁串行刷盘,导致后续COMMIT阻塞在waiting for handler commit状态。

binlog_cache_size写满后触发串行磁盘写入
不是“慢一点”,而是立刻卡住所有其他事务的 COMMIT。MySQL 为每个连接分配独立的 binlog cache(默认 5.7 是 32KB,8.0 是 128KB),DML 产生的 binlog event 全部先塞进去。一旦撑爆:
• MySQL 立即创建一个以 ML 开头的临时磁盘文件(如 mysql-bin.000001-#sql-xxxxx),把溢出内容刷进去
• 这个落盘动作由全局 LOCK_log 锁保护,多个事务同时触发时必须排队
• 后续所有线程执行 COMMIT 都卡在 waiting for handler commit 状态,直到大事务的缓存全部刷完
如何确认你正被这个机制堵死
别猜,直接查指标:
• 执行 SHOW STATUS LIKE 'binlog_cache%',重点关注 binlog_cache_disk_use 和 binlog_cache_use
• 如果前者 / 后者 > 5%,说明大量事务已在刷盘;接近 100% 就是典型阻塞信号
• 同时查 SHOW PROCESSLIST,状态为 waiting for handler commit 的线程,基本就是被堵住的受害者
• 错误日志里搜 ERROR 1197 或 Multi-statement transaction required more than 'max_binlog_cache_size' bytes,这是硬性报错,不是 IO 或权限问题
调大 binlog_cache_size 为什么常失效
它只是把问题往后推,还可能引发新风险:
• binlog_cache_size 是线程级私有内存,设成 4MB 后,100 个空闲连接就吃掉 400MB,高并发下极易 OOM
• max_binlog_cache_size 是熔断阀值(默认常为 4GB 或 16MB),超了直接报错 ERROR 1197,它不加速,只防崩
• 云厂商(如阿里云 RDS)通常锁死这两个参数,线上根本改不了
• ROW 格式下一条百万行 UPDATE 生成的 event 数量远超内存上限,再调参也扛不住——瓶颈在逻辑层,不在缓存大小
真正该盯住的两个活体指标
性能断崖的根源从来不是参数,而是运行中的事务本身:
• 查长事务:执行 SELECT * FROM INFORMATION_SCHEMA.INNODB_TRX WHERE trx_state = 'RUNNING' AND TIME_TO_SEC(TIMEDIFF(NOW(), trx_started)) > 60,找出没提交的“僵尸事务”
• 查卡点:SHOW PROCESSLIST 中状态为 waiting for handler commit 的线程,它们就是被堵死的实时证据
• 注意:一个 SLEEP 着却没 COMMIT 的事务,照样霸占着 cache 和已生成的 ML 临时文件,持续消耗 IO 资源


















