innodb_flush_log_at_trx_commit=1最安全但性能低,=2崩溃最多丢1秒事务,=0可能丢更多数据;需与sync_binlog协同配置防主从不一致,动态可调但需验证崩溃恢复效果。

innodb_flush_log_at_trx_commit 设成 0、1、2 到底影响什么
这个参数直接决定事务提交时日志是否刷盘,不是“性能开关”,而是“数据可靠性开关”。设错会导致 MySQL 在崩溃后丢事务,甚至丢数。
常见错误现象:innodb_flush_log_at_trx_commit=0 下突然断电,最近一秒的已提交事务全丢;=2 时主从延迟突增或 crash 后 binlog 和 redo 不一致。
-
=1(默认):每次COMMIT都调用fsync()写入磁盘。最安全,但写日志是串行瓶颈,高并发 insert/update 场景明显拖慢 TPS -
=2:每次COMMIT只写入 OS cache(write()),不fsync()。靠操作系统每秒刷一次。崩溃时最多丢 1 秒事务,但能扛住 MySQL 进程挂掉——前提是 OS 不崩 -
=0:事务提交完全不写 log buffer,由后台线程每秒刷一次。崩溃可能丢最多 1 秒 + 当前未刷的全部事务,仅适合纯测试或日志可丢场景
和 sync_binlog 一起配错了会丢数据
MySQL 主从复制依赖 binlog 和 redo 日志协同。如果 innodb_flush_log_at_trx_commit 和 sync_binlog 不匹配,crash 后可能出现“主库说事务成功了,但从库没收到对应 binlog”这种不一致。
典型踩坑场景:主库设 innodb_flush_log_at_trx_commit=2 + sync_binlog=1,OS 崩溃时 redo 没刷但 binlog 已刷,恢复后事务回滚,但从库已经执行了该 binlog —— 数据不一致。
- 强一致性要求(如金融):两个都设
1 - 接受秒级丢失但要主从一致:两个都设
0或都设2(注意sync_binlog=0是“每秒刷”,=2是“每次 commit 写 cache”) - 别混搭:比如
innodb_flush_log_at_trx_commit=1+sync_binlog=0,等于 redo 严守,binlog 放养,主从断裂风险陡增
怎么查当前值、在线改、改完要不要重启
它是个动态变量,SET GLOBAL 能立刻生效,不用重启 MySQL。但要注意:新连接才继承新值,已有连接的事务行为不变。
实操建议:
- 查当前值:
SELECT @@innodb_flush_log_at_trx_commit; - 临时修改(重启失效):
SET GLOBAL innodb_flush_log_at_trx_commit = 2; - 永久生效:必须写进
my.cnf的[mysqld]段,否则重启后回退到默认1 - 改完观察:
SHOW ENGINE INNODB STATUS\G里看Log sequence number和Log flushed up to的差值,差太大说明刷得慢,可能有瓶颈
SSD 和 NVMe 对这个参数的影响没你想的大
有人以为换 NVMe 就能把 =1 的性能拉上来,实际效果有限。因为 fsync() 不只是写设备,还涉及文件系统日志、page cache 锁、内核 I/O 调度路径。NVMe 缩短的是设备延迟,但整个刷盘链路的锁竞争和上下文切换开销没变。
真正起效的组合是:=1 + 开启 innodb_use_native_aio=ON(Linux)+ 文件系统用 XFS(避免 ext4 journal 拖累),再配合 NVMe 才有意义。
- 盲目换盘不调参数,
=2在 NVMe 上照样比=1快一倍以上 - OLTP 系统若 QPS > 5k,
=1很容易成为瓶颈,别硬扛 - 监控关键指标:
Innodb_os_log_fsyncs(每秒 fsync 次数)、Innodb_log_waits(log buffer 不够用等待次数),这两个飙升就说明日志刷不过来










