innodb_flush_log_at_trx_commit 是唯一能直接控制日志刷盘频率的核心参数:设为1每次提交都fdatasync()到磁盘,最安全但性能最低;设为2仅写入os缓存并每秒后台刷盘,mysql崩溃不丢数据但os崩溃最多丢1秒;设为0风险最高,mysql崩溃即丢整个log buffer(默认16mb),仅适用于压测或临时导入。

innodb_flush_log_at_trx_commit 是唯一能直接控制日志刷盘频率的核心参数,设为 1 就是每次提交都 fdatasync() 到磁盘,安全但慢;设为 2 是写进 OS 缓存即返回,每秒后台刷一次,多数业务可接受;设为 0 风险太高,除非压测或临时导入,否则别碰。
为什么不能只看“调高/调低”,而要看崩溃场景
值为 1 时,MySQL 崩溃不丢数据,但断电或内核 panic 仍可能丢最后一批已 fdatasync() 但未落盘的数据(取决于磁盘是否带掉电保护);值为 2 时,MySQL 崩溃不丢,OS 崩溃会丢最多 1 秒日志;值为 0 时,MySQL 崩溃就丢整个 log buffer(默认 16MB),可能是一整秒所有事务。金融、订单类系统必须用 1;日志上报、埋点类可选 2;开发库压测可临时切 0,但上线前得改回来。
改完没生效?注意连接级继承机制
执行 SET GLOBAL innodb_flush_log_at_trx_commit = 2 确实会立即生效,但它只影响新建立的连接。已有长连接(比如应用池里维持的连接)仍沿用旧值,不会自动更新。所以线上改完必须触发应用侧连接重连,或者滚动重启服务。不能只改参数就以为万事大吉。
和 sync_binlog 错配会放大问题
开启 binlog 的主库如果设了 sync_binlog = 1 却配 innodb_flush_log_at_trx_commit = 0,会出现两套日志不同步:redo 可能丢 1 秒,binlog 却已落盘,导致主从 GTID 跳变或复制中断。常见组合是:innodb_flush_log_at_trx_commit = 1 + sync_binlog = 1000(牺牲最多 1000 个事务的 binlog 持久性),或 innodb_flush_log_at_trx_commit = 2 + sync_binlog = 1000。监控时重点看 Innodb_os_log_fsyncs 和 Syncs_binlog 这两个状态变量的每秒增速是否合理。
真正难的不是选 0/1/2,而是确认你的硬件有没有掉电保护、文件系统是否禁用 write cache、监控是否真能捕获 fsync 延迟突增——这些细节一漏,参数再“合理”也白搭。











