会丢数据,但仅在特定崩溃场景下丢失最近1秒(设为0)或最多1秒(设为2)的事务日志;innodb数据文件仍受doublewrite和redo log保护,风险仅限未刷入ib_logfile的commit记录。

innodb_flush_log_at_trx_commit 设为 0/2 会丢数据吗?
会,但只在特定崩溃场景下丢最近 1 秒(设为 0)或最多 1 秒(设为 2)的事务日志,不是全量数据丢失。InnoDB 的数据文件(ibd)本身仍受 doublewrite 和 redo log 恢复机制保护,真正风险在于未刷入 ib_logfile 的那部分 commit 记录。
- 设为
1(默认):每次COMMIT都强制fsync到磁盘,强持久性,性能最差 - 设为
2:写入 OS 缓存即返回成功,每秒由后台线程fsync一次;断电且 OS 缓存未落盘时,最多丢 1 秒事务 - 设为
0:仅写入 log buffer,每秒刷一次到 OS 缓存 +fsync;MySQL 崩溃(非 OS 崩溃)时可能丢最多 1 秒,OS 崩溃则可能全丢
什么时候能放心调低 innodb_flush_log_at_trx_commit?
核心看业务对“已确认事务”的容忍边界——不是所有写操作都要求强持久。典型可调场景:
- 日志类、埋点类、统计汇总表等允许少量丢失的写入
- 内部工具后台任务,失败可重跑,且事务间无强依赖
- 读多写少 + 写入吞吐瓶颈明显,监控显示
Innodb_log_waits > 0或innodb_os_log_pending_fsyncs持续不为 0 - 使用了可靠的 UPS + 文件系统支持 barrier(如 ext4/xfs mount 时带
barrier=1),可降低2的风险
sync_binlog 和 innodb_flush_log_at_trx_commit 必须配对调吗?
必须。否则主从一致性或崩溃恢复会出问题。MySQL 5.7+ 在启用 binlog 时,若 sync_binlog != 1 且 innodb_flush_log_at_trx_commit != 1,无法保证 crash-safe replication。
- 要开启 GTID 或半同步复制,建议两个都设为
1 - 若接受主从延迟和小概率不一致,可设为
sync_binlog = 1000+innodb_flush_log_at_trx_commit = 2,但需确保binlog_format = ROW - 设为
0时,sync_binlog实际失效,因为 binlog 刷盘依赖于事务提交路径,此时 binlog 可能比 redo log 更滞后
调整后怎么验证效果和风险?
不能只看 TPS 上升,重点查三件事:日志刷盘压力是否缓解、崩溃恢复是否正常、主从延迟有无异常波动。
- 监控
SHOW GLOBAL STATUS LIKE 'Innodb_log_waits',值长期为 0 表示 log buffer 不再频繁等待刷盘 - 用
mysqladmin debug后检查 error log 中是否有Log sequence number跳变或 recovery warning - 模拟 kill -9 杀 MySQL 进程(非 service stop),重启后查
SELECT COUNT(*) FROM t WHERE ctime > '最近1秒时间戳'是否有记录缺失 - 对比调整前后
pt-stalk抓取的SHOW ENGINE INNODB STATUS,关注LOG小节中log i/o's done和pending log writes
fsync 延迟可能只有 0.1ms,但某些云盘(尤其共享型)的 fsync 延迟波动极大,有时单次超 50ms —— 这时候设成 1 反而比 2 更卡,得结合 iostat -x 1 看 await 和 %util 综合判断。











