测innodb_flush_log_at_trx_commit三种取值下2000次单行事务提交的耗时,看redo log刷盘策略的性能和安全性权衡。
innodb_flush_log_at_trx_commit控制事务提交时redo log到底落盘到什么程度。
代码SET GLOBAL innodb_flush_log_at_trx_commit=N; 循环2000次:INSERT一行,立刻commit
分别设成1、2、0三种取值测试。
结果innodb_flush_log_at_trx_commit=1: 2000次提交耗时 0.2514 s innodb_flush_log_at_trx_commit=2: 2000次提交耗时 0.1571 s innodb_flush_log_at_trx_commit=0: 2000次提交耗时 0.1758 s
结果符合预期的相对顺序:=1(最安全)最慢,=2最快。三者的具体含义是:=1 每次提交都把redo log刷到操作系统缓存、并调用fsync确保落到物理磁盘——最安全(哪怕操作系统崩溃、断电,已提交事务都不会丢),代价是每次提交都要等一次的磁盘同步。=2 每次提交只刷到操作系统缓存(write,不fsync),真正的物理落盘交给操作系统自己决定时机——如果只是MySQL进程崩溃,数据不会丢(操作系统缓存还在),但如果操作系统本身崩溃或断电,最后一小段可能丢失。=0 每次提交都不刷,只靠后台线程每秒刷一次——MySQL进程崩溃本身就可能丢失最近一秒的数据。
三个数字看着差距不算大(0.16~0.25秒之间),这本身也是的信息。
本机跑在的本地NVMe SSD上,fsync这个动作的延迟本身就很低——这解释了为什么 =1 和 =2/0 之间没有出现数量级的差距。场景里,如果磁盘是网络存储、机械硬盘,或者存在更高的I/O延迟,=1 每次提交都要付出的这次同步等待,差距会被放大很多——这也是为什么"要不要牺牲一点持久性换吞吐"是个要结合具体硬件环境判断的取舍,不是一个可以脱离环境直接下定论的数字。
=1——哪怕本机这次测得差距不算夸张,一旦发生进程崩溃或断电,=1 是唯一能保证"提交成功的事务不会丢"的选项,=2、=0 换来的吞吐提升,代价是用数据持久性做交换。
每一步都是本文上面用MySQL跑出来的原始耗时。
innodb_flush_log_at_trx_commit:对比0/1/2三种取值的耗时差异