开启binlog后写入变慢的主因是sync_binlog=1导致事务串行阻塞于fsync(),而非多记日志;调大binlog_cache_size、启用组提交(设sync_delay与no_delay_count)可显著优化。

binlog 开启后写入变慢,**不是因为“多记了一本日志”,而是因为默认配置强制每次事务都同步刷盘**。只要 sync_binlog = 1(默认值),MySQL 就必须在每个事务提交前,把 binlog 写满并 fsync() 到磁盘——这直接卡住事务提交路径。
为什么 sync_binlog=1 会让写入掉速?
这不是“慢”,是“串行阻塞”:所有并发事务排队等同一个 fsync() 完成才能返回。哪怕磁盘是 NVMe,单次 fsync() 也要 0.1–0.5ms;每秒 2000 个事务,就卡出 200ms+ 的平均延迟。
-
sync_binlog = 1时,Binlog 线程必须等fsync()返回,其他事务全在Writing to binlog状态挂起 -
sync_binlog = 0或sync_binlog = N (N > 1)可跳过实时刷盘,但需接受最多 N 条日志丢失风险 - 即使事务很小,只要并发高、
sync_binlog = 1,就会触发锁竞争和 I/O 放大,SHOW PROCESSLIST里能看到大量线程卡在该状态
组提交(Group Commit)为什么没生效?
MySQL 5.6+ 默认开启组提交,但**默认参数等于关掉了攒批逻辑**:binlog_group_commit_sync_delay = 0 表示“不等,来了就发”,根本凑不出一批事务。
- 设
binlog_group_commit_sync_delay = 100(单位微秒,即 0.1ms),让 Binlog 线程主动等一小会儿,大概率能攒到 5–20 个事务一起刷盘 - 搭配
binlog_group_commit_sync_no_delay_count = 10,防止低流量时一直卡住:积压够 10 个就立即发 - 这两个参数只在
sync_binlog = 1时起作用;设成 0 或 >1,组提交逻辑直接绕过 - 验证是否生效:查
SHOW GLOBAL STATUS LIKE 'Binlog_group_commit%',若Binlog_group_commit_trigger_delay明显上升(非零),说明 delay 起效了
binlog_cache_size 太小会偷偷拖慢大事务
大事务生成的 binlog 先缓存在内存里,等 COMMIT 才落盘。如果缓存不够,MySQL 会退到磁盘临时文件,I/O 开销翻倍。
- 默认
binlog_cache_size = 32768(32KB),批量更新 1 万行就可能溢出 - 观察
SHOW STATUS LIKE 'binlog_cache_disk_use':非零说明已在用磁盘缓存,必须调大 - 按单事务平均
binlog体积设值,例如 50MB 日志/小时 → 平均约 14KB/s → 单事务若耗时 10 秒,至少预留 140KB;稳妥起见设为20971520(20MB) - 注意:这是会话级变量,
SET SESSION binlog_cache_size = 20971520只对当前连接有效
别碰“看似省事”的错误优化
有些操作看起来能加速写入,实际对 binlog 完全无效,甚至引入一致性风险。
-
innodb_log_buffer_size增大只影响 Redo Log 缓冲,和binlog文件写入无关 -
innodb_flush_log_at_trx_commit = 2会拉快 InnoDB 提交,但让 Redo 和 Binlog 刷盘节奏脱钩,崩溃时可能丢数据或主从不一致 - 关闭
innodb_support_xa看似省开销,但大事务崩溃后极易出现 Binlog 有记录而 InnoDB 数据未落盘,主从同步直接中断 -
max_allowed_packet不够会导致单条语句生成的 Binlog event 被截断,报错Got a packet bigger than 'max_allowed_packet' bytes,哪怕事务已拆小
sync_binlog 和组提交参数的组合是否合理,以及 binlog_cache_size 是否撑得住业务事务量。调参前先看 SHOW PROCESSLIST 卡在哪、binlog_cache_disk_use 是否上升、Binlog_group_commit_trigger_delay 是否为 0——这些指标比猜更准。


















