innodb_flush_log_at_trx_commit=2 表示每次事务提交仅将redo log写入os page cache,不调用fsync,由内核每秒刷盘一次;它不是关闭持久性,而是权衡安全与性能的设计取舍,mysql崩溃不丢数据,但整机断电可能丢失最多1秒已提交事务。

innodb_flush_log_at_trx_commit=2 是什么,不是什么
它不是“关掉持久性”,而是把 redo log 的 fsync 从每次 COMMIT 挪到每秒一次——写入只进 OS page cache,由内核定时刷盘。这省掉了大量磁盘 I/O 等待,TPS 常提升 3~10 倍。
但它确实会丢数据:MySQL 进程崩溃时最多丢 1 秒已提交事务;整机断电且 OS cache 未落盘时同样可能丢失。这不是 bug,是设计取舍。
常见误判:innodb_flush_log_at_trx_commit=2 单独改了没效果?大概率是因为 sync_binlog 还卡在 1,redo log 快了,binlog 还在等 fsync,整体提交还是被拖住。
sync_binlog=0 和 sync_binlog=1000 怎么选
sync_binlog=0 表示 binlog 写入仅靠 OS 缓存,完全不主动 fsync;sync_binlog=1000 表示每 1000 次事务提交才刷一次 binlog 到磁盘。两者都能大幅降低刷盘压力,但风险不同:
-
sync_binlog=0:主从延迟不可控,崩溃后 binlog 可能比 redo log 少很多,GTID 或 position 容易断档,恢复困难 -
sync_binlog=1000:延迟有界(最多 1000 条事务),主从一致性更可控,适合多数高吞吐业务 - 云环境特别注意:部分 EBS gp3 或某些 NAS 盘未开启
disk_io_priority,sync_binlog=0可能反而因 OS 调度不及时导致写入抖动
为什么设成双2后反而变慢
调完 innodb_flush_log_at_trx_commit=2 和 sync_binlog=1000,TPS 不升反降,常见原因有:
-
innodb_log_file_size太小(默认 48MB),日志循环过快,频繁 checkpoint,触发脏页批量刷盘,IO 压力前移 - redo log 写入节奏和 buffer pool 刷脏能力不匹配:比如
innodb_io_capacity还按 HDD 设(200),SSD 实际可设 2000+,导致刷脏太保守、buffer pool 脏页堆积 - 并发线程数超过
innodb_buffer_pool_instances数量,所有线程争抢同一 buffer pool mutex,SHOW ENGINE INNODB STATUS中可见大量buf_pool_mutex等待 - 应用层还在用单行
INSERT INTO t VALUES (1)循环插入,网络往返+解析开销压垮连接线程,和日志参数无关
双写缓冲区(innodb_doublewrite)能不能关
MySQL 8.0.20+ 默认强制启用,运行时执行 SET GLOBAL innodb_doublewrite = OFF 会报错,除非满足严苛条件:未启用 innodb_checksum_algorithm = crc32 且 innodb_page_size = 16k。即使成功关闭,也只是降低约 10%~15% 写放大,换来的是崩溃后极大概率丢页、无法启动、只能靠备份恢复。
真正影响双写性能的是磁盘延迟,不是开关本身。如果你的 ibdata1 和数据文件混在一块慢盘上,优化方向应该是分离存储路径或换 SSD,而不是关双写。
别被“关双写提速”的旧文误导——现在 MySQL 8.0+ 的双写已是安全底线,不是性能开关。吞吐瓶颈真在这儿,说明你的 IO 子系统或 buffer pool 配置已经严重失衡,该查 Innodb_log_waits、Buffer pool hit rate 和磁盘 IOPS 了。











