会丢binlog;sync_binlog=0时依赖系统缓存,进程异常退出或断电会导致未刷盘binlog永久丢失,主从同步及pitr全部失效。

sync_binlog=0 时 MySQL 会丢 binlog 吗?
会,而且很可能丢。当 sync_binlog=0 时,MySQL 完全依赖操作系统缓存刷盘,只要 mysqld 进程异常退出(比如 OOM kill、kill -9、服务器断电),还没来得及写入磁盘的 binlog 就永久丢失。主从同步、基于 binlog 的恢复、闪回等全部失效。
常见错误现象:SHOW SLAVE STATUS 报错 Could not find first log file name in binary log index file,或从库突然跳过大量事务;用 mysqlbinlog 解析最新 binlog 文件发现末尾不完整甚至为空。
- 仅适合开发/测试环境,且能接受数据不可恢复
- 不能用于任何需要主从一致性或 PITR(时间点恢复)的场景
- 即使
innodb_flush_log_at_trx_commit=1,也不能弥补 binlog 丢失——两者是独立刷盘路径
sync_binlog=1 是最安全的选择吗?
是耐久性最强的设置,但不是“绝对安全”的银弹。它要求每次事务提交都调用 fsync() 刷 binlog 文件到磁盘,确保 binlog 和 InnoDB redo log 同时落盘(配合 innodb_flush_log_at_trx_commit=1),从而满足 ACID 中的 D(Durability)。
使用场景:金融、订单、支付等强一致要求系统;开启 GTID 且依赖 binlog 做逻辑复制的集群。
- 性能代价明显:高并发写入下,IOPS 瓶颈常卡在 binlog 的
fsync()上 - SSD 能缓解但不消除延迟;NVMe 盘比 SATA SSD 好约 2–3 倍吞吐
- 注意文件系统影响:XFS 比 ext4 在大文件
fsync()场景更稳定,ext4 的 journal 模式可能引入额外延迟
sync_binlog=N(N>1)怎么平衡丢数据风险和性能?
这是生产中最常被低估的折中方案。设为 sync_binlog=100 表示每累积 100 个事务才刷一次盘,既降低 fsync() 频次,又把最大丢失窗口控制在最近 N 个事务内(不是时间)。
关键理解点:N 不是“每 N 秒”,而是“每 N 个 commit 事件”。如果 QPS 是 5000,sync_binlog=100 ≈ 每 20ms 刷一次;若 QPS 掉到 100,则变成每秒刷一次。
- 必须配合监控:关注
Binlog_cache_use和Binlog_cache_disk_use,后者非零说明事务太大,缓存溢出到磁盘临时文件,反而更慢 - N 取值建议:从 10 或 50 开始压测,观察
Com_commit延迟和os.avg-disk-wait,避免盲目设成 1000+ - 注意 replication lag 波动:从库 IO 线程读取的是已刷盘的 binlog,所以 N 越大,主库“看起来”越快,但从库延迟抖动可能变大
为什么有些线上库设了 sync_binlog=1 却还是丢 binlog?
常见原因不是配置没生效,而是被更高优先级机制绕过了。最典型的是 binlog_format=STATEMENT 下执行了非确定性函数(如 NOW()、UUID()、用户变量),导致 MySQL 自动降级为 MIXED 并跳过某些事务的 binlog 记录;或者开启了 binlog_ignore_db 但匹配逻辑有误。
另一个隐蔽坑:sync_binlog 只对 *事务性* 写入生效。DDL(如 ALTER TABLE)在 MySQL 5.7+ 默认自动提交且不走事务缓存,其 binlog 刷盘行为受 sync_binlog 控制,但某些中间件或 ORM 的“伪事务”(autocommit=1 下连续 execute)可能让 DBA 误判刷盘节奏。
- 务必确认
SELECT @@sync_binlog返回值,而不是只看配置文件——动态修改后需验证 - 检查
SHOW VARIABLES LIKE 'binlog_format'和binlog_row_image,ROW 格式下更容易追踪实际写入内容 - 用
strace -p $(pgrep mysqld) -e trace=fsync,write抓真实系统调用,比日志更准
事情说清了就结束。真正难的不是选 0、1 还是 N,而是你得清楚自己能容忍几个事务不落地,以及磁盘到底能不能扛住那个 fsync 频率。











