MySQL数据落盘原理(redo、undo、binlog、2PC、double write等。)

MySQL数据落盘原理(redo、undo、binlog、2PC、double write等。)文章深入探讨了 MySQL 的事务持久性 特别是 InnoDB 存储引擎的落盘过程 包括从简单的直接写磁盘到使用缓存 redolog undolog doublewriteb 和 binlog 的复

大家好,欢迎来到IT知识分享网。


前言

ps:基于innodb存储引擎


一、架构图

首先通过几张图片宏观上了解MySQL和innodb的架构

1、MySQL架构图

mysql

2、InnoDB架构图

二、落盘分析

1.第一阶段

假设此时MySQL修改数据后直接写入磁盘,就会有一个问题,数据写入磁盘时随机写的,性能极差,于是有了第二阶段。

2.第二阶段

此阶段增加了缓存这一步,即MySQL修改数据后保存在缓存中,然后由后台线程异步写入磁盘,这个过程也有一个明显的问题,当数据还在缓存中尚未写入磁盘时系统崩溃,会导致数据丢失,安全级别相当差,于是有了第三阶段。

3.第三阶段

4.第四阶段

PS:关于undo log落盘
用户定义的临时表的 undo log不刷盘,非临时表的undo log要刷盘的,undo log记录了事务修改前逻辑日志,本质上是数据,和正常表区别不大,它的内容除了记录到undo tablespaces,也会被记录到redo log。其中刷盘到undo tablespaces的机制和正常表数据一致(异步刷盘),刷盘到redo log的机制是和该undo log其对应的redo log一起刷盘的。

5.第五阶段

此阶段增加了double write buffer,先将缓存中的数据搬到该缓冲区,再刷到共享表空间和各个独立表空间,细节如下:

double write由两部分组成,一部分是内存中的double write buffer,大小为2MB,另一部分是物理磁盘上共享表空间中连续的128个页,即2个区(extent),大小同样为2MB。在对缓冲池的脏页进行刷新时,并不直接写磁盘,而是会通过memcpy函数将脏页先复制到内存中的double write buffer,之后通过double write buffer再分两次,每次1MB顺序地写入共享表空间的物理磁盘上,然后马上调用fsync函数,同步磁盘,避免缓冲写带来的问题。在这个过程中,因为double write页是连续的,因此这个过程是顺序写的,开销并不是很大。在完成double write页的写入后,再将double write buffer中的页写入各个表空间文件中,此时的写入则是随机的,开销大。

这样就完美解决了 部分写失效 问题,即使写共享表空间失败,因为还没有写独立表空间,此时直接通过redo log恢复即可,如果写共享表空间成功,写独立表空间部分失败,先通过共享表空间的副本页恢复,再通过redo log恢复。

6.第六阶段

  • prepare 阶段
    write redo log到os cache,此时redo log是prepare标志
  • commit 阶段
    binlog落盘,此时把redo log标志由prepare变更为commit(表示redo log完整提交),再把redo log fsync到磁盘。

在MySQL崩溃恢复时,为了保证主从数据一致,检测到binlog完整(redo log至少prepare了),此时提交数据,如果binlog不完整或没有,则回滚数据,回滚用的redo log中的undo log的redo log(太绕了,好好梳理下)。

三、落盘总结

  • sync_binlog=0:表示每次提交事务只把log写到os cache,并不执行fsync刷盘,刷盘取决于操作系统;
  • sync_binlog=1:表示每次提交事务会将binlog刷盘(默认);
  • sync_binlog=N(N>=2): 表示每次提交事务只把log写到os cache,等累积到N个才执行fsync刷盘;

redo log的重要参数是innodb_flush_log_at_trx_commit:

  • 0 – 每N秒将Redo Log Buffer的记录写入Redo Log文件,并且将文件刷入硬件存储1次。N由innodb_flush_log_at_timeout控制;
  • 1 – 每个事务提交时,将记录从Redo Log Buffer写入Redo Log文件,并且将文件刷入硬件存储;
  • 2 – 每个事务提交时,仅将记录从Redo Log Buffer写入Redo Log文件。Redo Log何时刷入硬件存储由操作系统和innodb_flush_log_at_timeout决定。这个选项可以保证在MySQL宕机,而操作系统正常工作时,数据的完整性。

根据参数含义可知,最安全的就是双1配置,在双1配置下可以得到如下分析:

四、崩溃恢复

在讲崩溃恢复之前首先要说一下mysql 崩溃恢复时先rollforward(利用redo log恢复data和undo log),再rollback(利用undo log回滚到历史版本)。

  • 崩溃时刻A: 事务提交之前,此时事务没提交,肯定回滚,纵使后台page cleaner线程已经将data和undo log刷盘。
  • 崩溃时刻B: xa_prepare阶段,此时redo log处于xa prepare阶段,binlog未刷盘,肯定回滚,纵使因redo log被写入os cache而落了盘,另外binlog未刷盘,不会传播到从库。
  • 崩溃时刻C: xa_commmit阶段,此时binlog执行了刷盘,redo log尚未commit。需要根据xid关联binlog与redo log,若binlog不完整,则回滚事务,完整则提交事务。
  • 崩溃时刻D: xa_commmit阶段,binlog已刷盘,redo log也commit,事务完整提交。

ps:

  • 1: MySQL如何确定binlog完整性?
    一个事务的binlog有完整格式:
    statement格式,最后会有commit;
    row格式,最后会有个xid_log_event;
    MySQL 5.6.2版本后,引入binlog-checksum机制,验证binlog内容正确性。对于binlog日志由于系统崩溃等原因,可能会在写入日志中途出错,MySQL通过进行checksum校验binlog完整性。



  • 2:redo log、binlog如何关联?
    二者有个共同数据字段XID。崩溃恢复时,会从最后一次checkpoint的位置开始顺序扫描redo log,若碰到既有prepare、又有commit的redo log,直接提交事务。若碰到只有prepare、无commit的redo log,就拿XID去binlog找对应事务,此时若binlog完整则提交事务,否则回滚事务。

免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://haidsoft.com/138058.html

(0)
上一篇 2025-06-15 19:33
下一篇 2025-06-15 19:45

相关推荐

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注微信