MySQL 双一原则为什么能保证数据不丢

501 阅读2分钟

小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。

在日常工作或者面试中,我们经常会谈到,即使 INNODB 事务提交了,数据还是有可能会丢,那么这是什么原因呢。

其实这就聊到了“双一原则”,即 sync_binlog = 1 && innodb_flush_log_at_trx_commit = 1。今天我们就来聊一聊为什么双一原则能保证数据不丢。

  • 先看一下 redo log 刷到磁盘的步骤:

    1. 当事务提交时,会先将数据写入到 Log Buffer 中,这里调用的是 MySQL 自己的 WriteRedoLog;
    2. 接着,之后当 MySQL 发起系统调用写文件 write 时,Log Buffer 中的日志才会写到操作系统缓存中(OS Cache);
    3. 注意,当 MySQL 系统调用完 write 之后,就会认为文件已经写完,如果不 flush,什么时候落盘,是由操作系统决定的。
    4. 最后,由操作系统将 OS Cache 中的数据刷到磁盘上。
  • 同样,再看一下 binlog 刷到磁盘的步骤:

    1. 事务执行过程中,先把日志写到 binlog cache 中;
    2. 事务提交,将 binlog cache 中的数据写入到操作系统缓存中;
    3. 最后,由操作系统决定什么时候将数据刷到磁盘上;
  • 说一下 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 主动将文件系统缓存中数据批量刷到磁盘;

因此,我们可以看到,双一原则保证数据不丢的原因是:每次事务提交都将数据刷到磁盘中,这是非常重要的。