大事务导致binlog_cache_size频繁刷盘并阻塞COMMIT:默认值过小(5.7为32KB、8.0为128KB),超限后触发串行磁盘写入,使后续COMMIT排队;可通过SHOW STATUS监控binlog_cache_disk_use是否接近binlog_cache_use来判断,并谨慎调大binlog_cache_size(如设为4MB),但根本解法是识别高binlog产出SQL、优化binlog_format(如切至MIXED)或拆分事务。

大事务让 binlog_cache_size 频繁刷盘,COMMIT 开始排队
不是所有大事务都会立刻写磁盘,很多卡在 binlog_cache_size 内存里就堵死了。MySQL 每个连接独享一份缓存,默认仅 32KB(5.7)或 128KB(8.0)。一旦事务产生的 binlog event 超过该值,就会触发串行磁盘临时文件写入——后续所有 COMMIT 都得等它完成。
查是否已频繁落盘:SHOW STATUS LIKE 'binlog_cache%';若 binlog_cache_disk_use 接近或等于 binlog_cache_use,说明几乎每个事务都在刷盘。
- 临时调参可缓解:比如
SET GLOBAL binlog_cache_size = 4194304(4MB),但别设太高(>512MB)——连接数多时易引发单机内存暴涨 -
max_binlog_cache_size不是性能参数,而是熔断开关:超限直接报错ERROR 1197 (HY000),默认值常为 4GB 或 16MB,云厂商可能锁死无法修改 - 该参数只对当前会话生效的事务起作用,且必须小于
max_allowed_packet,否则仍失败
ROW 格式下一条 UPDATE 可能生成百万级 binlog event
盲目调大 binlog_cache_size 只是掩盖问题。真正该先做的,是识别谁在疯狂产 binlog。例如:UPDATE t SET c=1 WHERE id BETWEEN 1 AND 1000000 在 ROW 模式下会生成百万级 event;STATEMENT 模式下就只有 1 条。
查当前格式:SHOW VARIABLES LIKE 'binlog_format';确认业务是否真需要 ROW 级精度(如涉及函数、触发器、不安全 SQL 的复制场景)。
- 非必要场景建议切到
MIXED:自动降级为 STATEMENT,仅在必要时用 ROW - 切之前务必验证从库兼容性,尤其注意
last_insert_id()、SLEEP()、UDF 等函数行为差异 - 切完观察
SHOW BINARY LOGS文件增长速率,对比调整前后单事务日志体积
PURGE 前不核对主从位置,删掉的 binlog 从库还没读完
大事务不仅让单个 binlog 文件远超 max_binlog_size(比如一个 5GB UPDATE 写出 5.2G 的 mysql-bin.000123),更关键的是它拉长了主从延迟窗口——你不敢删的 binlog,很可能正卡在从库 relay log 里没执行完。
安全清理三步缺一不可:
- 查主库当前日志:
SHOW MASTER STATUS→ 记下File字段(如mysql-bin.000123) - 查从库同步状态:
SHOW SLAVE STATUS\G→ 看Relay_Master_Log_File和Exec_Master_Log_Pos - 只允许删
mysql-bin.000122及更早的;命令示例:PURGE BINARY LOGS TO 'mysql-bin.000123'
expire_logs_days=0 是默认陷阱,云上实例常被锁死
MySQL 默认 expire_logs_days = 0,官方明确表示“不启用自动清理”。哪怕每天只跑几百条 INSERT,只要 log-bin 开启,日志就持续累积——RDS 实例可能因此触发“锁定中”状态。
注意版本差异:
- MySQL 5.7:配
expire_logs_days = 7(单位天),写进my.cnf的[mysqld]段并重启最稳妥 - MySQL 8.0+:必须用
binlog_expire_logs_seconds = 604800(7 天),二者共存会导致启动报错3683 - 云厂商(如阿里云 RDS)可能禁用该参数,此时只能靠定时
PURGE+ 外部监控告警兜底
真正难处理的,是那些既不能改格式、又不能拆事务、还跑在云托管环境里的存量业务——这时候盯紧 binlog_cache_disk_use 和 SHOW PROCESSLIST 里长时间 Committing 的线程,比调参更管用。


















