innodb_flush_log_at_trx_commit=1、2、0分别对应每次提交强制fsync、仅写入OS缓存(每秒刷盘)、完全依赖后台每秒刷盘,安全性递减而性能递增;需协同sync_binlog调整并按写入速率合理设置redo log总容量与buffer大小。

高并发写入卡顿,八成是 Redo Log 刷盘策略太激进,而不是磁盘慢。 默认 innodb_flush_log_at_trx_commit=1 要求每次事务都 fsync 到磁盘,在 SSD 上也扛不住每秒几千次小事务提交。调对参数能直接把写入吞吐翻倍,但必须清楚每种取值的真实行为和业务容忍边界。
innodb_flush_log_at_trx_commit 设成 0、1、2 到底差在哪
这不是“安全 vs 性能”的模糊权衡,而是三种完全不同的落盘路径:
-
innodb_flush_log_at_trx_commit=1:事务提交时,MySQL 自己调用write()+fsync(),数据真正落到磁盘。崩溃不丢事务,但延迟最高 -
innodb_flush_log_at_trx_commit=2:事务提交只调write(),日志进 OS 缓存(page cache),由内核每秒fsync一次。断电或 mysqld 崩溃可能丢失最多 1 秒事务 -
innodb_flush_log_at_trx_commit=0:事务提交不触发任何写操作,全靠内核每秒刷一次 OS 缓存。进程崩溃或断电可能丢最近 1 秒所有事务,且无法保证 binlog 和 redo log 一致
关键点:=2 不等于“基本安全”,它依赖 OS 的可靠性;=0 在 MySQL 8.0+ 主从架构中极易导致复制中断,慎用。
为什么单改 innodb_flush_log_at_trx_commit=2 还是慢
单独调这个参数效果有限,因为 binlog 刷盘会形成新瓶颈。常见错误组合是 innodb_flush_log_at_trx_commit=2 + sync_binlog=1:
- 事务提交时,redo log 只进 OS 缓存,但 binlog 强制
fsync—— 两者不同步,主从复制可能报错binlog checksum mismatch - 必须协同调整:
sync_binlog=0(彻底交由 OS 控制)或sync_binlog=1000(每千次事务刷一次),才能释放全部吞吐 - 监控
Innodb_os_log_pending_fsyncs,如果持续 > 0,说明 OS 缓存积压严重,=2已经不够用,得查磁盘或内核参数
Redo Log 文件大小怎么定才不抖动
不是越大越好,也不是拍脑袋填 2G,而是按你真实的写入速率反推:
- 先跑
SHOW GLOBAL STATUS LIKE 'Innodb_os_log_written';,隔 60 秒再查一次,差值 ÷ 60 = 每秒日志写入字节数(比如 12MB/s) - 目标 checkpoint 间隔 ≥ 60 秒 → 推荐总容量 ≈
12 * 60 * 2≈ 1.4GB(留 100% 余量) - MySQL 8.0.30+ 必须用
innodb_redo_log_capacity(单位字节),旧配置里的innodb_log_file_size会导致启动失败 - 修改后必须停库,手动删掉
ib_logfile0和ib_logfile1(或整个#ib_redo*目录),否则启动报错log file is of different size
大事务写入卡住?可能是 innodb_log_buffer_size 太小
该缓冲区只缓存事务内产生的 redo 日志,不是数据页本身。默认 16MB 在批量插入或含大 JSON/BLOB 的更新中很容易打满:
- 当事务产生的 redo 日志超过 buffer 容量,会强制 flush 并等待——
Innodb_log_waits计数上升就是信号 - 对单事务写入量 > 1MB 的场景(如 Java
executeBatch(10000)),建议设为 64MB 或更高 - 注意:该值只影响“事务执行中”的日志生成效率,不影响持久性保障;调太大浪费内存,没必要超 256MB
最易被忽略的是:Redo Log 优化从来不是单点动作。buffer 大小、刷盘策略、文件总容量、binlog 同步频率必须匹配业务写入特征——某一项没对齐,其他调优都会打折扣。


















