应先通过SHOW STATUS LIKE 'Binlog_cache%'确认Binlog_cache_disk_use/ Binlog_cache_use>5%及错误日志中ERROR 1197,再定位高产binlog事务并分批拆解,而非盲目调大binlog_cache_size。
直接调大 binlog_cache_size 不仅治标不治本,还可能引发内存雪崩;真正要解决 Binlog 暴增和 IO 压力,得先定位“谁在产巨量 event”,再分层干预。
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 很危险这个参数是每个连接独占的内存,不是全局共享池:
max_binlog_cache_size 是熔断阀值,不是性能参数;默认 4GB 已足够,调太高反而让一个事务拖垮整实例autocommit=1 的单条语句走的是 binlog_stmt_cache_size,排查时混淆这两者会误判瓶颈UPDATE t SET c=1 WHERE id BETWEEN 1 AND 1000000 可能生成百万级 event,缓存再大也扛不住——它卡在逻辑层,不是内存层参数只是兜底手段,以下动作对生产稳定性影响更大:
SET GLOBAL long_query_time = 0.1; + SET GLOBAL log_slow_admin_statements = ON;,重点盯 COMMIT 耗时异常的线程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 查原始 SQLWHERE id BETWEEN x AND y + LIMIT 5000 控制粒度,既降锁时间,也自然规避缓存压力expire_logs_days 是否设为 0(永不清理),max_binlog_size 是否过大(如 2GB),避免单个 binlog 文件过大导致 mysqlbinlog 解析失败或磁盘打满mysqlbinlog 因文件太大解析失败时怎么办常见报错是 Error writing file '/tmp/xxx' (Errcode: 28 - No space left on device),这不是 MySQL 配置问题,而是 mysqlbinlog 自己在 /tmp 生成临时文件撑爆磁盘:
tmpdir,mysqlbinlog 不读这个参数;它用的是系统 gettempdir() 或环境变量 TMPDIR
TMPDIR=/data/tmp mysqlbinlog -v mysql-bin.003300 > out.sql,确保目标路径有足够空间--base64-output=DECODE-ROWS 避免解码膨胀;或加 --start-position/--stop-position 分段解析,避开大事务所在区间真正难的不是调哪个参数,而是判断「这个大事务是否合理」——如果业务逻辑本就不该批量更新百万行,那所有调优都是给坏设计擦屁股。监控 Binlog_cache_disk_use 是入口,但终点一定是代码和 SQL 的改造。