“双1”即innodb_flush_log_at_trx_commit=1且sync_binlog=1,是mysql崩溃后事务不丢失的最低安全底线;前者确保redo log每次提交都fsync落盘,后者确保binlog同步写入磁盘,二者缺一不可,否则将导致数据页可恢复但主从复制断裂或备份不可用。

必须同时设为 1:innodb_flush_log_at_trx_commit 和 sync_binlog,缺一不可;否则崩溃后事务可能“半存半丢”。
为什么只开 innodb_flush_log_at_trx_commit=1 不够
它只保证 redo log 落盘,但 binlog 还卡在 OS page cache 里——重启后 InnoDB 能恢复数据页,可主从复制位点断了、GTID 跳变、用 mysqlbinlog 做时间点恢复会失败。典型现象是:SELECT 能查到数据,SHOW SLAVE STATUS 显示 Seconds_Behind_Master: NULL 或 IO/SQL Thread stopped。
- 设
innodb_flush_log_at_trx_commit=1但sync_binlog=0:binlog 写入后不 fsync,掉电时日志文件末尾丢失 - 设
sync_binlog=1但innodb_flush_log_at_trx_commit=0:redo log 每秒刷一次,掉电最多丢 1 秒事务,且 binlog 有而数据页没恢复,造成主从不一致 - 两者都为 1 才构成“双一”,是 MySQL 崩溃后事务不丢失的最低安全底线
怎么确认配置真的生效了
改完 my.cnf 不等于落地。MySQL 启动时若遇到路径错误、权限不足或语法问题(比如写成 ON 而非 1),会静默忽略并沿用默认值。
- 进库执行:
SHOW VARIABLES LIKE 'innodb_flush_log_at_trx_commit'和SHOW VARIABLES LIKE 'sync_binlog',两个结果都必须是1 - 常见失效场景:Docker 官方镜像默认
sync_binlog=0;配置放错目录(如/etc/my.cnf.d/但 MySQL 实际读/etc/mysql/my.cnf);用了云厂商托管实例却未开启“高可靠模式” - 动态 SET 修改(如
SET GLOBAL innodb_flush_log_at_trx_commit = 1)立即生效,但重启后丢失,必须写入配置文件
硬件和 OS 层面的依赖不能跳过
哪怕两个参数都是 1,如果底层不配合,fsync 就是假成功——日志看似落盘,实则还躺在磁盘控制器缓存里,掉电即蒸发。
- 磁盘需支持真实 fsync:禁用 write-back 缓存(
hdparm -W0 /dev/sdX),或使用带电容保护的 NVMe/SSD - 文件系统挂载选项必须含
data=ordered(ext4)或mount -o sync(XFS);barrier=0会直接废掉 fsync 语义 - 不要信“硬件原子写”宣传——当前主流 MySQL 二进制包未启用该路径,InnoDB 16KB 页无法被 SSD 原子保障
别忘了 innodb_doublewrite 和校验和
它们不防事务丢失,但防崩溃后启动失败或静默损坏——这类问题常被误判为“数据丢了”,其实是数据库压根起不来或返回脏数据。
-
innodb_doublewrite必须保持ON(默认),关掉会导致部分写失效(torn write),启动时卡在 recovery 或报Database page corruption on disk -
innodb_checksum_algorithm应设为crc32(5.7+ 默认),它能在读取页时主动报错,阻止损坏页进入缓冲池;设成none或strict_crc32反而让崩溃更难诊断 - 检查方式:
SHOW VARIABLES LIKE 'innodb_doublewrite'看是否为ON;SELECT @@innodb_checksum_algorithm看是否为crc32
真正容易被忽略的是:参数生效 ≠ 链路可信。从 COMMIT 返回成功,到数据能扛住断电,中间横跨 InnoDB、OS、文件系统、磁盘固件四层,任何一层绕过 fsync 或禁用 barrier,整个“双一”就形同虚设。











