这里是目录标题
先来一张数据库系统架构图
一. Redo Log—InnoDB存储引擎的日志文件
Redo Log是InnoDB存储引擎的日志文件,其写入磁盘的操作如下图
1. 操作流程
当发生数据修改的时候,innodb引擎会先将记录写到redolog中,并更新内存,此时更新就算是完成了,同时innodb引擎会在合适的时机将记录操作到磁盘中
2. 特点
- RedoLog是固定大小的,是循环写的过程。
- write pos 是当前记录的位置,一边写一边后移,写到第 3 号文件末尾后就回到 0 号文件开头。checkpoint 是当前要擦除的位置,也是往后推移并且循环的,擦除记录前要把记录更新到数据文件。write pos 和 checkpoint 之间的是还空着的部分,可以用来记录新的操作。如果 write pos 追上 checkpoint,表示redo log满了,这时候不能再执行新的更新,得停下来先擦掉一些记录,把 checkpoint 推进一下。有了 redo log,InnoDB 就可以保证即使数据库发生异常重启,之前提交的记录都不会丢失,即 crash-safe。
3. 作用
有了RedoLog之后,InnoDB就可以保证即使数据库发生异常重启,之前的记录也不会丢失,即crash-safe
二. Undo Log—回滚/前滚日志
Undo Log是为了实现事务的原子性,在Mysql的InnoDB引擎中,还用Undo Log来实现多版本并发控制(MVCC)
1. 操作流程
在操作任何数据之前,首先将数据备份到Undo Log中,然后进行数据的修改。如果出现了错误或者用户执行了ROLLBACK操作,系统可以利用Undo Log中的备份将数据恢复到事务之前的状态
2. 特点
Undo Log是逻辑日志
- 当delete一条数据时,Undo Log中会记录一条对应的insert记录
- 当insert一条数据时,Undo Log中会记录一条对应的delete记录
- 当update一条数据时,Undo Log会记录一条相反的update记录
3. 作用
实现事务的原子性,InnoDB引擎中,还用Undo Log来实现多版本并发控制(MVCC)
4. 回滚日志什么时候删除?
答:在不需要的时候才删除,系统会判断,当没有事务再用到这些回滚日志时,其就会被删除。
什么时候才不需要呢?
答:系统里没有比这个回滚日志更早的read-view时。
read-view是啥?
在RC(Read Committed)和RR(Read Repeatable)隔离级别下,会通过Read-View视图实现隔离。Read-View视图和数据库创建虚拟表的那个视图不是一个东西。RC级别下,每个查询语句开始时都会先创建一个Read-View。RR级别下,每个事务开始时都会先创建一个Read-View,事务中的所有操作都会基于这个Read-View。其实现都是基于回滚日志,详情见MVCC:https://aobing.blog.csdn.net/article/details/109044141
为甚么建议你尽量不要使用长事务?
答:1. 长事务意味着系统里会存在很老的Read-View,由于这些事务随时可能访问数据库里的任何数据,所以这个事务提交之前,数据库里面它可能用到的回滚记录都必须保留,这就会导致大量占用存储空间。2. 长事务还占用锁资源,可能拖垮整个库。
三. BinLog—服务端的日志文件
BinLog是server层的日志文件(见文章开头的架构图中间的Server层),主要负责数据库功能层面的事,比如数据恢复、主从复制等等。
默认不开启,可通过设置log_bin
属性开启
1. 特点
BinLog会记录所有的逻辑,采用追加写的方式
2. 作用
- 一般在企业中用于数据备份
- 恢复数据:
- 找到最近一次的全量备份数据
- 从备份的时间点开始,将备份的BinLog取出来,重放到要恢复的那个时刻
3. 与Redo Log的区别
- Redo Log是InnoDB独有的,BinLog所有的引擎都可以使用
- Redo Log是物理日志,记录了在某个数据页上做了什么修改。BinLog是逻辑日志,记录了某条语句的原始操作
- Redo Log是循环写的,空间用完会覆盖之前的日志。BinLog是追加写的,不会覆盖之前的日志
4. binlog一天一备和一周一备的对比
答:一天一备的最长恢复时间(RTO,恢复目标时间)更短。
一天一备的最坏情况需要应用一天的binlog。比如,每天0点做一次全量备份,而要恢复出一个到昨天晚上23点的备份。
一周一备的最坏情况就要应用一周的binlog。
但是备份是有成本的,更频繁全量备份需要消耗更多的存储空间,所以这个RTO是成本换来的,就需要根据业务的重要性来评估了。
四. 数据更新流程
1. RedoLog两阶段提交策略
- binlog有记录,redolog状态commit:正常完成的事务,不需要恢复
- binlog有记录,redolog状态prepare:在binlog写完提交事务之前的crash,恢复操作:提交事务
- binlog无记录,redolog状态prepare:在binlog写完之前的crash,恢复操作:回滚事务
- binlog无记录,redolog无记录:在redolog写之前crash,恢复操作:回滚事务
2. BinLog的三阶段提交策略
引入队列机制保证innodb commit顺序与binlog落盘顺序一致,并将事务分组,组内的binlog刷盘动作交给一个事务进行,实现组提交目的。binlog提交将提交分为了3个阶段,FLUSH阶段,SYNC阶段和COMMIT阶段。每个阶段都有一个队列,每个队列有一个mutex保护,约定进入队列第一个线程为leader,其他线程为follower,所有事情交由leader去做,leader做完所有动作后,通知follower刷盘结束。binlog组提交基本流程如下:
FLUSH 阶段
(1) 持有Lock_log mutex [leader持有,follower等待]
(2) 获取队列中的一组binlog(队列中的所有事务)
(3) 将binlog buffer到I/O cache
(4) 通知dump线程dump binlog
SYNC阶段
(1) 释放Lock_log mutex,持有Lock_sync mutex[leader持有,follower等待
(2) 将一组binlog 落盘(sync动作,最耗时,假设sync_binlog为1
COMMIT阶段
(1) 释放Lock_sync mutex,持有Lock_commit mutex[leader持有,follower等待]
(2) 遍历队列中的事务,逐一进行innodb commit
(3) 释放Lock_commit mutex
(4) 唤醒队列中等待的线程
说明:由于有多个队列,每个队列各自有mutex保护,队列之间是顺序的,约定进入队列的一个线程为leader,因此FLUSH阶段的leader可能是SYNC阶段的follower,但是follower永远是follower。
3. 为甚么Redo Log要有两阶段提交?
为了保证数据一致性,保证redo log和binlog中的数据是一致的,不会错乱
- 先写redo log,后写binlog
如果redo log写完了,binlog还没写完,这时系统崩了。如果需要使用binlog进行数据恢复,那么恢复的数据会和redo log中记录的不一致,比原库少了一次更新
- 先写binlog,后写redo log
写完binlog,还没写完redo log时系统又崩了,所以该事务无效。那么使用binlog进行数据恢复的时候,就会比redo log多了一个事务,数据又不一致了