君哥聊技术

面试官:MySQL Redo Log 和 Undo Log 有什么区别?分别用在什么场景?

大家好,我是君哥。国庆快乐。

MySQL 有三大日志体系,Redo Log、Undo Log 和 Binlog,其中 Undo Log 和 Redo Log 都是 InnoDB 存储引擎特有的日志。今天就来聊一聊 MySQL Redo Log 和 Undo Log 的区别。

1.Undo Log

1.1 MVCC

MVCC 中文名称叫多版本并发控制,是InnoDB 引擎为了提高执行事务的并发效率引入的概念。多版本的含义就是一条数据被多个事务修改后,在事务还没有被提交前,存在多个版本。MVCC 的实现机制就是通过版本链把多个版本连接起来。

比如我们有一个库存表,记录了主键 id,商品编号(goods_no)和库存数量(stock_count)。商品编号等于 10 的记录,初始状态 stock_count 是 100,事务一进行修改后 stock_count 变成 98,事务二进行修改后变成 95。

在事务一修改商品编号等于 10 的这条记录之前,InnoDB 会先把 stock_count 等于 100 的原始记录保存到 Undo Log,修改后的版本会保存指向原始记录的 Undo Log 指针。同样,事务二修改这条记录之前,InnoDB 会将事务一修改后(stock_count 等于 98)的记录保存到 Undo Log,事务二修改后的记录保存指向这条 Undo Log 记录的指针。这样对同一条数据的修改形成了一个版本链,如下图:

Image

为了实现版本链,InnoDB 引擎在每行记录中会添加 3 个隐藏的列:

  • DB_TRX_ID:修改(插入、更新或删除)这一条数据的事务 id;
  • DB_ROLL_PTR:回滚指针,也就是上面说的指向前一个历史版本的指针,用于回滚操作。
  • DB_ROW_ID:当表中不定义主键时用作主键来自动生成聚簇索引。

1.2 Undo Log

在 InnoDB 中,事务为了保证原子性,必须要实现整个事务的回滚,这就需要记录数据被修改前的状态(比如插入或删除了一条记录,修改了一条记录),记录这些修改前状态的日志就是 Undo Log。

Undo Log 主要有两个作用:

  • 原子性:事务可以通过 Undo Log 来实现回滚,从而实现原子性;
  • 一致性:如果另一个事务需要将原始数据视为一致性读取操作的一部分,则从 Undo Log 中检索未修改的数据。
  • MVCC:多版本并发控制中的多个版本,就是通过 Undo Log 来记录的。

Undo Log 保存在 undo log segments, 而 undo log segments 则保存在 Rollback Segment。 Rollback segment 保存在 undo 表空间(undo tablespaces)和全局临时表空间(global temporary tablespace)。

Image

Rollback Segment 能支持的事务数量取决于自己能保存多少 undo slot 和每个事务需要多少个 undo slot。在一个页大小是 16KB 的 InnoDB 引擎中,每个 Rollback Segment 能保存 1024 个 undo slot。

每个事务只能使用一个 Rollback Segment,一个 Rollback Segment 同一时刻可以会服务于多个事务。

那 Undo Log 什么时候清理呢?需要两个条件:事务已经提交,并且 Undo Log 已经过期(即保存时间超过 undo retention 参数指定的时间)。

当然,即使达到清理的条件,也不会立刻清理,因为 Undo Log 所在的 Rollback Segment 页可能被其他未提交的事务使用(数据页使用未满3/4)。

对于 insert 操作产生的 Undo Log,因为只对本事务可见,所以事务提交后 Undo Log 就可以立刻删除。而对于 update 和 delete 操作,可能存在 MVCC 版本链的使用,不能在事务提交后立刻删除。

Undo Log 具备删除条件时,会放入队列,等待后台 purge 线程删除。

2.Redo Log

Redo Log 也是 InnoDB  存储引擎特有的日志,它是一个物理日志,记录了在某个数据页上做了哪些修改,主要用于崩溃恢复。

2.1 写日志

在写日志时,Redo Log 是循环写,空间大小固定,写满后会覆盖掉前面的日志。

Redo Log 采用固定大小的文件组,比如下图文件组配置了 4 个文件,每个文件大小相同,写满一个后接着写下一个,全部写满后就清除一部分前面的日志,继续写入。write pos 控制当前写入的位置,check point 控制可以写入的最后位置,如果两个点重合了,那就需要清除部分日志,让 check point 后移。

Image

2.2 崩溃恢复

Redo Log 主要用于崩溃恢复。它确保了数据库宕机后,已提交事务的数据不会丢失。Redo Log 基于 WAL (Write-Ahead Logging) 原则,即先写日志,再写磁盘。事务提交时,先将修改内容的记录到 Redo Log,MySQL 宕机重启后,利用 Redo Log 做崩溃恢复。恢复过程如下图:

Image

首先,InnoDB 会检查数据页的 LSN (日志序列号),并与 Redo Log 中的 LSN 对比。Redo Log 上 LSN 比数据页大的就是需要重做的数据。 接着,InnoDB 会扫描 Redo Log 中要恢复的日志,如果日志状态是 COMMIT,则直接重做。如果日志状态是 PREPARE,则还要去检查对应的 Binlog,如果该事务的 Binlog 存在且完整,说明事务已经提交成功,应该重做。如果该事务的 Binlog 不存在或不完整,说明事务应该回滚,Redo Log 日志不进行重做。

通过这个机制,确保了 Redo Log 和 Binlog 的逻辑一致性:只要 Binlog 写成功了,数据就一定能够被恢复;如果 Binlog 没写成功,说明事务应该被回滚,数据无需恢复。

3.区别

总结 Undo Log 和 Redo Log 区别如下:

区别点
Undo Log
Redo Log
作用
事务回滚和MVCC
奔溃恢复
日志类型
逻辑日志(记录修改前的数据状态)
物理日志(记录做了哪些修改)
生命周期
在事务中数据修改前写入,事务提交并且具备删除条件后被清理。
事务进行中写入 ,事务提交后可以被覆盖。
清理方式
purge 线程清理
循环写入,被覆盖。
存储位置
undo 表空间和全局临时表空间
磁盘 ib_logfile 文件

最后,我们再以下面的 SQL 为例,看一下记录日志的过程:

update tb_stock set stock_count = 98where goods_no = 10;
Image
精品专栏 70 篇,推荐阅读。
又老性能又差,为什么好多公司依然选择 RabbitMQ?

45 个知识点,带你入门消息队列!

引入了 Disruptor 后,系统性能大幅提升!

 从 MySQL 迁移到 GoldenDB,上来就踩了一个坑。

面试官:MySQL BETWEEN AND 语句包括边界吗?

面试官:MySQL Redo Log 和 Binlog 有什么区别?分别用在什么场景?

面试官:使用 MySQL 时你遇到过哪些索引失效的场景

面试官:MySQL表中有2千万条数据,B+树层高是多少?

面试官:MySQL JOIN 表太多,你有哪些优化思路?

感谢阅读,如果对你有帮助,请点赞和在看。欢迎加我微信:zhujinjun86。

号内回复 seata,下载《阿里分布式中间件Seata从入门到精通》

号内回复 beijing,下载我总结的北京上百家知名科技公司

号内回复 aqs,下载《40张图精通Java AQS》