innodb_flush_log_at_trx_commit:Redo 日志的持久化策略
搞 MySQL 运维也好,开发也罢,时间长了就会发现,事务提交这一步,看着简单,里面的门道可不少。就说那个 Redo 日志吧,它就跟咱们平时记账用的那个草稿纸似的,你列如说,把 id=10 那行记录的 name 字段改成 “李四”,这个操作就会先被记到 Redo 日志里。这些日志一开始是存在内存的 Redo Log Buffer 里的,至于啥时候把它们写到硬盘的文件里,就得看
innodb_flush_log_at_trx_commit这个参数是咋设置的了。
这个参数有三个选项,选哪个,主要就看你是更看重数据的安全,还是更追求数据库的速度了:
• 设成 0 的时候:提交事务的时候,Redo 日志根本不会立马往硬盘上写,全靠着 InnoDB 的主线程每秒跑一次,批量把它们刷新到硬盘。这事儿就有个麻烦,要是 MySQL 突然之间崩了,内存里那些还没刷到硬盘的日志就全没了,最近提交的那些事务可能就白弄了。我之前帮一个朋友的小电商网站调数据库的时候,他们为了图快,就把这个参数设成 0 了,结果有一次突然断电,丢了几十条订单记录,从那后来,他们再也不敢这么弄了。
• 设成 1 的话:这可是最稳妥的办法了 —— 事务提交的时候,必须得把 Redo 日志从内存刷到硬盘的文件里。不过这里我得多说一句,操作系统这东西有点 “懒”,有时候你觉得已经写到硬盘了,实则呢,它只是放到自己的缓冲区里了,还得再执行个 sync 之类的操作才算真的进到硬盘里。但不管怎么说,只要事务提示提交成功了,那 Redo 日志肯定已经安全地存在磁盘相关的地方了,这一点是肯定的。
• 设成 2 的时候:提交事务的时候,Redo 日志会先被丢进操作系统的缓存,也就是 OS Cache 里,不是直接就进到硬盘文件里。这些缓存里的东西,大致 1 秒之后会自己同步到硬盘。这种方式比设成 1 的时候快挺多,但是呢,要是操作系统挂了,缓存里的日志可能就没了。我之前见过一些做日志分析的系统用这个参数,他们觉得丢个一两秒的数据没啥大不了的,能换点性能提升,挺值的。
所以你看啊,只有设成 1,才能保证事务肯定是持久化了,但缺点也很明显 —— 每次提交都得等着硬盘慢悠悠地写完,MySQL 跑起来就没那么快了。要是你的业务能接受偶尔丢点数据,就像那些实时性要求高,但数据不怎么重大的场景,那设成 0 或者 2,的确 能让数据库快不少。
想看看自己数据库目前这个参数是啥配置,敲下面这条命令就行:
select @@innodb_flush_log_at_trx_commit;

sync_binlog:二进制日志的刷新控制
说完了 Redo 日志,再来说说二进制日志,也就是 Binlog。这东西可重大了,数据库所有的修改操作它都记着,不管是恢复数据,还是做主从复制,都离不了它。而sync_binlog这个参数,就管着 Binlog 啥时候从内存写到硬盘上。
这个参数能设成 0、1,或者任意一个正整数 N,它们的脾气可是不一样的:
• 设成 0 的时候:这是默认的设置,事务提交之后,Binlog 会从缓冲区写到硬盘,但不会执行刷新操作,列如 fsync 之类的。说白了,就是放到操作系统的缓冲区里了,要是操作系统突然挂了,那些没来得及同步到硬盘的日志就丢了。
• 设成 1 的话:事务提交的时候,Binlog 不仅要写到硬盘,还得立刻执行刷新操作,确保直接进了硬盘,不经过系统的缓存。这种方式最保险,但是频繁地往硬盘上写东西,肯定会影响性能。我之前维护过一个银行
的核心数据库,这个参数就必须设成 1,哪怕慢一点也没关系,数据可不能出半点差错。
• 设成 N 的时候:每往操作系统的缓冲区里写 N 次,才执行一次刷新操作。列如说设成 100,那就是往缓冲区里写 100 次之后,才会同步到硬盘。这种方式能让性能提高一点,但风险也跟着来了 —— 万一出点啥事儿,最多可能会丢 N 条日志记录。
一般来说,要是你的数据库涉及到数据恢复,或者做主从复制,要求数据严格一致,那 sync_binlog 最好设成 1。当然了,代价就是性能会受点影响,这就跟咱们寄快递一样,想加急又想保险,那肯定得多花点钱,道理是一样的。




学习一下