undo log 回滚日志

Innodb 存储引擎层生成的日志,实现了事务中的原子性,主要用于事务回滚和MVCC。

undo log是一种用于撤销回退的日志。在事务没提交前,MySQL会先记录更新前的数据到undo log日志文件里面,当事务回滚时,可以利用undo log 来进行回滚。 如下图:

image-20231030104531461
  • 插入一条记录时,要把这条记录的主键值记下来,这样之后回滚时只需要把这个主键值对应的记录删掉就好了;
  • 删除一条记录时,要把这条记录中的内容都记下来,这样之后回滚时再把由这些内容组成的记录插入到表中就好了;
  • 更新一条记录时,要把被更新的列的旧值记下来,这样之后回滚时再把这些列更新为旧值就好了。

一条记录的每一次更新操作产生的 undo log 格式都有一个 roll_pointer 指针和一个 trx_id 事务id:

  • 通过 trx_id 可以知道该记录是被哪个事务修改的;
  • 通过 roll_pointer 指针可以将这些 undo log 串成一个链表,这个链表就被称为版本链;

版本链如下图:

image-20231030105445664

另外, undo log 还有一个作用,通过ReadView + undo log 实现 MVCC (多版本并发控制)

undo log 两大作用:

  • 实现事务回滚,保障事务的原子性。事务处理过程中,如果出现了错误或者用户执 行了 ROLLBACK 语句,MySQL 可以利用 undo log 中的历史数据将数据恢复到事务开始之前的状态。
  • 实现 MVCC(多版本并发控制)关键因素之一。MVCC 是通过 ReadView + undo log 实现的。undo log 为每条记录保存多份历史数据,MySQL 在执行快照读(普通 select 语句)的时候,会根据事务的 Read View 里的信息,顺着 undo log 的版本链找到满足其可见性的记录。

redo log 重做日志

Innodb 存储引擎层生成的日志,实现了事务中的持久性,主要用于掉电等故障恢复。

Buffer Pool 是基于内存的,而内存总是不可靠。

为了防止断电导致数据丢失的问题,当有一条记录需要更新的时候,InnoDB 引擎就会先更新内存(同时标记为脏页),然后将本次对这个页的修改以 redo log 的形式记录下来,这个时候更新就算完成了

后续,InnoDB 引擎会在适当的时候,由后台线程将缓存在 Buffer Pool 的脏页刷新到磁盘里,这就是 WAL (Write-Ahead Logging)技术

WAL 技术指的是, MySQL 的写操作并不是立刻写到磁盘上,而是先写日志,然后在合适的时间再写到磁盘上

过程如下图:

image-20231030110842998

redo log什么时候刷盘

主要有下面几个 timing:

  • MySQL 正常关闭时;
  • redo log buffer中记录的写入量大于redo log buffer内存空间的一半时,会触发落盘
  • InnoDB 的后台进程每隔1s,将redo log buffer 持久化到磁盘
  • 每次事务提交时都将缓存在 redo log buffer 里的 redo log 直接持久化到磁盘

binlog 归档日志

是Server层生成的日志,主要用于数据备份和主从复制。