Bin log、Redo log、Undo log详解以及为甚么事务要两阶段提交?

先来一张数据库系统架构图

Bin log、Redo log、Undo log详解以及为甚么事务要两阶段提交?

一. Redo Log—InnoDB存储引擎的日志文件

Redo Log是InnoDB存储引擎的日志文件,其写入磁盘的操作如下图
Bin log、Redo log、Undo log详解以及为甚么事务要两阶段提交?

1. 操作流程

当发生数据修改的时候,innodb引擎会先将记录写到redolog中,并更新内存,此时更新就算是完成了,同时innodb引擎会在合适的时机将记录操作到磁盘中
Bin log、Redo log、Undo log详解以及为甚么事务要两阶段提交?

2. 特点

  1. RedoLog是固定大小的,是循环写的过程。
  2. write pos 是当前记录的位置,一边写一边后移,写到第 3 号文件末尾后就回到 0 号文件开头。checkpoint 是当前要擦除的位置,也是往后推移并且循环的,擦除记录前要把记录更新到数据文件。write pos 和 checkpoint 之间的是还空着的部分,可以用来记录新的操作。如果 write pos 追上 checkpoint,表示redo log满了,这时候不能再执行新的更新,得停下来先擦掉一些记录,把 checkpoint 推进一下。有了 redo log,InnoDB 就可以保证即使数据库发生异常重启,之前提交的记录都不会丢失,即 crash-safe。

Bin log、Redo log、Undo log详解以及为甚么事务要两阶段提交?

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)

三. BinLog—服务端的日志文件

BinLog是server层的日志文件(见文章开头的架构图中间的Server层),主要负责数据库功能层面的事,比如数据恢复、主从复制等等。
默认不开启,可通过设置log_bin属性开启

1. 特点

BinLog会记录所有的逻辑,采用追加写的方式

2. 作用

  1. 一般在企业中用于数据备份
  2. 恢复数据:
  1. 找到最近一次的全量备份数据
  2. 从备份的时间点开始,将备份的BinLog取出来,重放到要恢复的那个时刻

3. 与Redo Log的区别

  • Redo Log是InnoDB独有的,BinLog所有的引擎都可以使用
  • Redo Log是物理日志,记录了在某个数据页上做了什么修改。BinLog是逻辑日志,记录了某条语句的原始操作
  • Redo Log是循环写的,空间用完会覆盖之前的日志。BinLog是追加写的,不会覆盖之前的日志

四. 数据更新流程

Bin log、Redo log、Undo log详解以及为甚么事务要两阶段提交?

1. RedoLog两阶段提交策略

  1. binlog有记录,redolog状态commit:正常完成的事务,不需要恢复
  2. binlog有记录,redolog状态prepare:在binlog写完提交事务之前的crash,恢复操作:提交事务
  3. binlog无记录,redolog状态prepare:在binlog写完之前的crash,恢复操作:回滚事务
  4. 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中的数据是一致的,不会错乱

  1. 先写redo log,后写binlog

如果redo log写完了,binlog还没写完,这时系统崩了。如果需要使用binlog进行数据恢复,那么恢复的数据会和redo log中记录的不一致,比原库少了一次更新

  1. 先写binlog,后写redo log

写完binlog,还没写完redo log时系统又崩了,所以该事务无效。那么使用binlog进行数据恢复的时候,就会比redo log多了一个事务,数据又不一致了