确认 binlog_cache_size 溢出需查 SHOW STATUS LIKE 'Binlog_cache%',若 Binlog_cache_disk_use/Binlog_cache_use > 5% 或错误日志出现 ERROR 1197,即为确证;盲目调大该参数会引发内存暴涨且无效,应定位高产 binlog 的 SQL 并分批执行。

直接调大 binlog_cache_size 或 max_binlog_cache_size 不能解决 Binlog 缓存溢出问题,只会掩盖事务设计缺陷——真正要做的,是定位高产 binlog 的 SQL 并拆分执行。
怎么确认真是 binlog_cache_size 溢出?
别一看到 COMMIT 慢就改参数。先查运行时指标:
- 执行
SHOW VARIABLES LIKE 'binlog_cache_size',确认当前值(5.7 默认 32KB,8.0 默认 128KB) - 立刻执行
SHOW STATUS LIKE 'Binlog_cache%',重点看Binlog_cache_use和Binlog_cache_disk_use - 如果
Binlog_cache_disk_use/Binlog_cache_use> 5%,说明大量事务被迫写临时文件,且这个磁盘写是串行的——后续所有COMMIT都在排队 - 错误日志里搜
ERROR 1197或Failed to write to binlog cache,这是最硬的证据
为什么盲目调大 binlog_cache_size 很危险?
这个参数是每个连接独占的内存,不是全局共享池:
- 设成 64MB 后,100 个空闲连接就吃掉 6.4GB 内存
- 云数据库(如阿里云 RDS)通常锁死该参数,改了也无效
-
max_binlog_cache_size是熔断阀值,不是性能参数;默认 4GB 已足够,调太高反而让一个事务拖垮整实例 -
autocommit=1的单条语句走的是binlog_stmt_cache_size,排查时混淆这两者会误判瓶颈 - ROW 格式下,一条
UPDATE t SET c=1 WHERE id BETWEEN 1 AND 1000000可能生成百万级 event,缓存再大也扛不住——它卡在逻辑层,不是内存层
如何定位并拆分高产 binlog 的事务?
比调参更关键的是识别谁在生成巨量 binlog:
- 开启慢日志捕获长事务:
SET GLOBAL long_query_time = 0.1+SET GLOBAL log_slow_admin_statements = ON,重点盯COMMIT耗时异常的线程 - 用 SQL 定位高产 binlog 的事务:
SELECT trx_id, trx_started, trx_rows_modified FROM information_schema.INNODB_TRX ORDER BY trx_rows_modified DESC LIMIT 5,再关联performance_schema.events_statements_current查原始 SQL - 把 100 万行更新改成每批 5000 行,用
WHERE id BETWEEN x AND y+LIMIT 5000控制粒度,既降锁时间,也自然规避缓存压力 - 同步检查
expire_logs_days是否设为 0(永不清理),max_binlog_size是否过大(如 2GB),避免单个 binlog 文件过大导致mysqlbinlog解析失败或磁盘打满
真正容易被忽略的点:ROW 格式下,trx_rows_modified 基本等于 binlog event 数量;而 STATEMENT 格式下,哪怕影响百万行,也只记一条 event。但切格式前得确认业务是否依赖行级变更回放——比如有触发器、函数、非确定性语句的场景,切过去可能丢数据或复制不一致。


















