InnoDB引擎架构:
InnoDB引擎的内存部分:
包括 用于存放数据的缓冲池BufferPool;
用于 暂存RedoLog,之后统一刷到磁盘的RedoLogBuffer ;
用于 避免数据从 内存 刷回到 磁盘 过程中 出错,而引入的DoubleWriteBuffer
描述一个DML语句的执行流程:
(假设该DML语句是一个UPDATE语句,该语句作为一个事物要求InnoDB执行)
【MySQL执行器会涉及哪些操作?MySQL Server 涉及 binlog 但是好像不操作UndoLog RedoLog 啥的吧】
1.MySQLServer执行器根据DML语句从InnoDB引擎内存BufferPool中找数据,若不在,从磁盘中load该内容对应的页到BufferPool中
这块涉及的点在于:优化的LRU
2. 引擎根据DML生成UndoLog,并将UndoLog写回到InnoDB磁盘区中存放UndoLog的地方
问题一:UndoLog的具体内容是什么?
UndoLog中记录一条与DML相反的命令:
例如:DML执行:UPDATE table1 set age = 10 where id=1 ;
而原来 id=1的age为5
那么,UndoLog中生成的命令就是:UPDATE table1 set age = 5 where id=1 ;
==》这样,当事务发生错误,可以通过UndoLog来回滚到事务执行前的状态
问题二:UndoLog 的作用 ?
1. 提供回滚操作【undo log实现事务的原子性】MySQL就要执行回滚(rollback)操作,利用undo log将数据恢复到事务开始之前的状态。
2. 提供多版本控制(MVCC)【undo log实现多版本并发控制(MVCC)】当读取的某一行被其他事务锁定时,它可以从undo log中分析出该行记录以前的数据版本是怎样的,从而让用户能够读取到当前事务操作之前的数据【快照读】。
【有些操作只能获得快照读 -- MVCC的内容(MVCC如何根据UndoLog来实现多版本,UN到哦Log是如何存放回滚指针事务链的),可以链接补充在这里】
问题三:UndoLog 如何指导回滚操作 ?
1. 当MySQLServer 对值进行修改Or值修改完但是值还存放在InnoDB引擎内存中时,总之就是MySQL寄了,内存中新值或者半新半旧的值还没刷回到磁盘中就没了,
==》回滚,那么就使用UndoLog恢复之前的状态新的值在内存中但是
为什么 Undo Log不也搞一个Undo Log Buffer,也给Undo Log提提速,【不确定是否存在Undo Log Buffer,因此这个问题存疑】
那我们假设有这个一个Buffer存在于InnoDB,将事务开始前的数据状态写入了Undo Log Buffer中,然后开始更新数据。
突然啪一下,很快啊,MySQL由于意外进程退出了,此时会发生一件很尴尬的事情,如果更新的数据一部分已经刷回磁盘了,但是此时事务没有成功需要回滚,你发现Undo Log随着进程退出一起没了,此时就没有办法通过Undo Log去做回滚。
那如果刚刚更新完内存,MySQL就挂了呢?此时Redo Log Buffer甚至都可能没有写入,即使写入了也没有刷到磁盘,Redo Log也丢了。
其实无所谓,因为意外宕机,该事务没有成功,既然事务事务没有成功那就需要回滚,而MySQL重启后会读取磁盘上的Redo Log文件,将其状态给加载到Buffer Pool中。而通过磁盘Redo Log文件恢复的状态和宕机前事务开始前的状态是一样的,所以是没有影响的。然后等待事务commit了之后就会将Redo Log和Binlog刷到磁盘。
3. MySQL Server 执行器 解析 DML语句,对数据进行操作(更新 id=1的条目其age的值),调用引擎接口将新的age值重新写入,引擎则把这个新的数据存放在 BufferPool中
涉及的问题是:何时将BufferPool中的 数据 刷盘到 磁盘文件中
以及刷盘前 MySQL寄了,
刷盘中 MySQL寄了,
两种情况下的处理办法
4. 引擎 把数据存放在 BufferPool,同时 引擎将该语句执行后的数据状态 写入到 RedoLogBuffer中。当事务全部执行完毕,附上内部XA事务的ID并将状态置为Prepare。此时可以根据RedoLog指定的策略将RedoLog刷盘到磁盘中了。
(之所以经过一次 RedoLogBuffer的中转是因为一个事务可能不止有一条DML语句,多个DML语句生成的RedoLog内容先暂存到RedoLog Buffer中,当事务结束,再一起(减少IO)刷回到 磁盘的RedoLog空间中)
redo log buffer中的数据也不是直接入盘,中间还会经过操作系统内核空间的缓冲区
os buffer,然后才到磁盘上的redo log file。innodb_flush_log_at_trx_commit参数可以控制redo log buffer何时写入redo log file,该参数有三个可选值,分别如下:
0:延迟写。不会在事务提交时立即将redo log buffer写入到os buffer,而是每秒写入os buffer,然后立即写入到redo log file,也就是每秒刷盘
1:实时写,实时刷。每次事务提交都会将redo log buffer写入os buffer,然后立即写入redo log file。数据能够及时入盘,但是每次事务提交都会刷盘,效率较低
2:实时写,延时刷。每次事务提交都将redo log buffer写入os buffer,然后每秒将os buffer写入redo log file
5. RedoLog写入到磁盘成功后,将BinLog 同样写入到磁盘的对应BinLog空间,同样也记录BinLog对应的XA 事件ID。此时InnoDB引擎新启一个线程将BufferPool中的数据刷到磁盘中( 只要保证日志先行:先写了RedoLog,再把BufferPool数据刷回磁盘)
mysql checkpoint技术: mysql checkpoint技术 - 简书 (jianshu.com)
6. 当binLog刷回到磁盘中时,MySQL Server执行器调用InnoDB存储引擎的提交API,将RedoLog对应的事务状态标识修改为Commit。
4、5、6三步就是 为了实现 RedoLog和Binlog在事务提交时的数据一致性 而采用的 两提交2PC协议
为什么要保证Redo Log和Binlog在事务提交时的数据一致性呢?
在两阶段提交的不同时刻,MySQL 异常重启会出现什么现象?
1. 当RedoLog内容写入到磁盘中,MySQL异常:
此时:BinLog还在内存中,因此BinLog数据丢失,同时,磁盘中的RedoLog李对于该事务的标记还只是Prepare。
==》崩溃恢复时,由于事务没有提交,那么,调用UndoLog 回滚
2. binlog 写到磁盘,redolog 还没被标记为 commit 前 MySQL异常:
那崩溃恢复的时候 MySQL 会怎么处理?
崩溃恢复的规则:
7. MySQL Server执行器调用InnoDB存储引擎的接口提交事务,整个过程结束。
Ref:
玩转MySQL:InnoDB引擎存储结构+特性ChangeBuffer和DoubleWriter分析 - 知乎 (zhihu.com)
必须了解的MySQL三大日志:binlog、redo log和undo log - 知乎 (zhihu.com)
为什么需要redo log
我们都知道,事务的四大特性里面有一个是持久性,具体来说就是只要事务提交成功,那么对数据库做的修改就被永久保存下来了,不可能因为任何原因再回到原来的状态。那么mysql是如何保证一致性的呢?最简单的做法是在每次事务提交的时候,将该事务涉及修改的数据页全部刷新到磁盘中。但是这么做会有严重的性能问题,主要体现在两个方面:
- 因为Innodb是以页为单位进行磁盘交互的,而一个事务很可能只修改一个数据页里面的几个字节,这个时候将完整的数据页刷到磁盘的话,太浪费资源了!
- 一个事务可能涉及修改多个数据页,并且这些数据页在物理上并不连续,使用随机IO写入性能太差!
因此mysql设计了redo log,具体来说就是只记录事务对数据页做了哪些修改,这样就能完美地解决性能问题了(相对而言文件更小并且是顺序IO)。
MySQL--buffer pool、redo log、undo log、binlog_黄智霖-blog的博客-CSDN博客
数据库系列3:InnoDB的结构和更新语句执行的详细过程_innodb 历史zhixing语句_纵横千里,捭阖四方的博客-CSDN博客
数据库系列2:更新语句执行的基本过程_纵横千里,捭阖四方的博客-CSDN博客
MySQL中两个重要的日志(redolog和binlog)_数据库两个日志文件怎么写_wy471x的博客-CSDN博客
mysql checkpoint技术 - 简书 (jianshu.com)
基于Redo Log和Undo Log的MySQL崩溃恢复流程 - 知乎 (zhihu.com)
mysql redo log为什么有两阶段提交/为什么有prepare和commit两个状态?_redolog prepare_wu@55555的博客-CSDN博客
mysql 物理日志之redo log(重做日志)原理和介绍 - 简书 (jianshu.com)
锁、乐观悲观锁 这块 看看第四节视频里面有没有,没有就看看理解一下记录一下,这块重点常考【是吧】
一个总结的比较全面的MySQL内容;【单机MySQL】