小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。
在日常工作或者面试中,我们经常会谈到,即使 INNODB 事务提交了,数据还是有可能会丢,那么这是什么原因呢。
其实这就聊到了“双一原则”,即 sync_binlog = 1 && innodb_flush_log_at_trx_commit = 1
。今天我们就来聊一聊为什么双一原则能保证数据不丢。
-
先看一下 redo log 刷到磁盘的步骤:
- 当事务提交时,会先将数据写入到 Log Buffer 中,这里调用的是 MySQL 自己的 WriteRedoLog;
- 接着,之后当 MySQL 发起系统调用写文件 write 时,Log Buffer 中的日志才会写到操作系统缓存中(OS Cache);
- 注意,当 MySQL 系统调用完 write 之后,就会认为文件已经写完,如果不 flush,什么时候落盘,是由操作系统决定的。
- 最后,由操作系统将 OS Cache 中的数据刷到磁盘上。
-
同样,再看一下 binlog 刷到磁盘的步骤:
- 事务执行过程中,先把日志写到 binlog cache 中;
- 事务提交,将 binlog cache 中的数据写入到操作系统缓存中;
- 最后,由操作系统决定什么时候将数据刷到磁盘上;
-
说一下 MySQL 的两阶段提交:
- 先 prepare;
- 写 binlog;
- 写 redo log;
- commit;
-
为什么会丢数据?
- binlog 认为写入到文件系统缓存就算成功了;(个人理解)
- redo log 认为写入到 Log Buffer 中就算成功了;(个人理解)
- 所以只要没有写入磁盘都会丢数据;
-
如何保证不丢?
- 写完缓存,再刷新到磁盘上,数据就能保证不丢;
- 双一策略都要求落盘才会成功;
-
sync_binlog
参数配置:0
:每次提交事务只写入到文件系统缓存,并不会把数据持久化到磁盘,速度较快;1
:每次提交事务都持久化到磁盘;N
:(N>1)每次提交事务都把数据写入到文件系统缓存,但是累计 N 个事务后才把数据刷到磁盘
-
innodb_flush_log_at_trx_commit
参数配置:0
:每隔 1 秒,才会将 Log Buffer 中的数据批量写入到文件系统缓存,并刷到磁盘;(有可能会丢 1 秒数据)1
:每次事务提交,都会将 Log Buffer 中的数据写入到文件系统缓存,并刷到磁盘。(是 MySQL 默认配置,保证事务 ACID 特性)2
:每次事务提交,都将 Log Buffer 中的数据写到文件系统缓存,每隔 1 秒,MySQL 主动将文件系统缓存中数据批量刷到磁盘;
因此,我们可以看到,双一原则保证数据不丢的原因是:每次事务提交都将数据刷到磁盘中,这是非常重要的。
扫描二维码关注公众号,回复:
13167342 查看本文章
