6 张图吃透Undo log,MySQL进阶必知必会!

Undo log 回滚日志是 MySQL 进阶必知必会的一个重要知识点,大厂面试也经常会被问到。

Undo Log 回滚日志记录事务执行过程中的旧值,当事务发生异常、需要回滚操作时,可使用 Undo Log 来撤销事务的变更操作,将数据恢复到事务开始之前的状态,从而确保事务的一致性,提高数据库的并发性能和系统的稳定性。

6 张图吃透Undo log,MySQL进阶必知必会!

大家好,我是爱分享的程序员宝妹儿。

本篇深入:Undo log 回滚日志的物理结构、以及其在事务中的流程。

 

PS.

 Binlog :例如:binlog从基础到精通系列图解bin log、redo log及undo log区别等,宝妹儿已将内容更新到《MySQL 大厂高频面试题大全》PDF了,方便系统学习、面试通关。

MySQL PDF100+7830000

MySQL

6 张图吃透Undo log,MySQL进阶必知必会!

1. Undo log 基础知识

上一篇 图解 Undo log 的存储机制及工作原理 ,介绍了

  • Undo log 的概念
  • Undo log 的两大作用
  • Undo log 的存储机制
  • Undo log 的工作原理

点击蓝字回顾: 图解 Undo log 的存储机制及工作原理

2. Undo log 的作用

Undo log 的两大作用分别是提供数据回滚、多版本控制 MVCC。

  • 提供数据回滚(原子性)

事务具有 ACID 特性,其中,”A”代表事务的原子性(Atomicity)。

即:事务中的所有操作要么全部成功执行,要么全部回滚。

undo log(回滚日志)回滚操作是实现原子性的关键,它保证了事务的 ACID 特性中的原子性。

undo log 是一种用于撤销回退的日志,在事务没提交之前,MySQL 会先记录更新前的数据到 undo log 日志文件里面,当事务回滚时或数据库崩溃时,可以利用 Undo Log 进行数据回滚。

6 张图吃透Undo log,MySQL进阶必知必会!

  • 多个行版本控制 MVCC

undo log 还有一个作用,通过 ReadView + undo log 实现 MVCC。

当用户读取某个记录时,如果这个记录已被其它的事务所占用,通过 Undo Log  读取之前的行版本信息,当前事务就可以实现非锁定读取。

undo log 为每条记录保存多份历史数据,MySQL 在执行快照读(普通 select 语句)的时候,会根据事务的 Read View 里的信息,顺着 undo log 的版本链找到满足其可见性的记录。

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

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

版本链如下图:

6 张图吃透Undo log,MySQL进阶必知必会!

3. Undo log 的物理结构

Undo log 的物理结构

Undo log 的物理结构,由上到下分别为:

  • 回滚表空间
  • 回滚段 (undo log segment)
  • undo log slot
  • page

6 张图吃透Undo log,MySQL进阶必知必会!

Undo log 由 128 个回滚段(Rollback segment)构成。

其中,32 个回滚段用于系统的临时表空间,96 个回滚段用于事务。

  • slot 0 ,预留给系统表空间;
  • slot 1- 32,预留给临时表空间,每次数据库重启的时候,都会重建临时表空间;
  • slot 33-127,如果有独立表空间,则预留给UNDO独立表空间;如果没有,则预留给系统表空间。

回滚段中除去 32 个提供给临时表事务使用,剩下的 128-32=96个回滚段,可执行 96*1024 个并发事务操作,每个事务占用一个 undo segment slot。

  • 如果事务中有临时表事务,在临时表空间中的 undo segment slot 会再占用一个 undo segment slot,即占用2个 undo segment slot。
  • 如果错误日志中有 Cannot find a free slot for an undo log,说明并发的事务太多了,需要考虑是否分流业务。

每个回滚段对应一个 segment header page,在这个 page 中又划分了 1024 个 slot,每个 slot 又对应到一个 undo log 对象。

独立表空间的 space id 是从 1  开始的,0 被预留在 ibdata 中,space id 是连续分配、并且不能断档的。

回滚段

重点聊下回滚段。

回滚段(Rollback Segment)由多个回滚段组成,是存储 Undo log 的数据结构,每个回滚段有多个 undo log slot,负责存储特定范围的事务 Undo log 。

回滚段采用轮询调度的方式来分配使用,如果设置了独立表空间,就不会使用系统表空间回滚段中 undo segment,而是使用独立表空间,同时,如果回滚段正在 Truncate 操作,则不分配。

InnoDB 在 undo tablespace 中使用回滚段来组织 undo log,以及维护 undo log 的并发写入和持久化。

通过 Rollback Segment Header 来管理回滚段,Rollback Segment Header 的结构:

6 张图吃透Undo log,MySQL进阶必知必会!

回滚段update_undo、insert_undo 两种类型

update_undo:

  • 只用于事务内的 update 和 delete 语句。
  • 加入到其对应 rollback segment 的 history list 数据页列表上,history list 长度加1。
  • 该 log 需要提供 MVCC 机制,因此不能在事务提交时就进行删除。提交时放入 undo log 链表,等待 purge 线程进行清除。

insert_undo:

  • 只用于事务内的 insert 语句。
  • 新插入的记录产生的 undo 不会被任何查询语句所引用,因此可以直接释放 undo,此处 undo log 不会累加到 history list 上。insert 操作的记录只对事务本身可见,因此,该 undo log 不需要进行 purge 操作,在事务提交后就直接删除。

delete 和 update 操作最终都是由 purge 来完成的。

  • innodb_purge_batch_size:全局动态参数,默认值为 300,用来设置每次 purge 操作需要清理的 undo page 数量。
  • innodb_max_purge_lag:全局动态参数,用来控制 history list 的长度,若大于该参数时,其会延缓 DML 的操作。
  • innodb_max_purge_lag_delay:全局动态参数,用来控制 DML 操作每行数据的最大延缓时间,单位为毫秒。
    6 张图吃透Undo log,MySQL进阶必知必会!

可以通过如下几个参数对回滚段做配置:

innodb_undo_log_truncate

  • InnoDB 的 purge 线程,根据 innodb_undo_log_truncate 设置开启或关闭、innodb_max_undo_log_size 的参数值,以及 truncate 的频率来进行空间回收和 undo file 的重新初始化。
  • 该参数生效的前提是,已设置独立表空间且独立表空间个数大于等于 2 个。

innodb_max_undo_log_size

  • 控制最大的 undo tablespace 文件大小,当启动了 innodb_undo_log_truncate 、且 undo tablespace 超过 innodb_max_undo_log_size 阀值时,才会去尝试 truncate 。
  • 该值默认大小为 1G,truncate 后的大小默认为 10M。

innodb_undo_tablespaces

  • 设置 undo 独立表空间个数,范围为 0-128, 默认为 0,0 表示不开启独立 undo 表空间、且 undo日志存储在 ibdata 文件中。
  • 该参数只能在最开始初始化 MySQL 实例的时候指定,如果实例已创建,这个参数是不能变动的,如果在数据库配置文件 .cnf 中指定 innodb_undo_tablespaces 的个数大于实例创建时的指定个数,就会启动失败,并提示该参数设置错误。

innodb_undo_directory

  • 设置 rollback segment 文件所在位置的路径,这意味着 rollback segment 可以存放在共享表空间以外的位置,即可以设置为独立表空间。
  • 该参数的默认值为“.”,标识当前InnoDB存储引擎的位置的目录。

innodb_undo_log

  • 用来设置 rollback segment 的个数。
  • 默认值为128个。

4. Undo log 在事务中的流程

事务在 undo log segment 分配、且写入 undo log 的同时,也会产生 redo log。

当事务提交时(commit):

  • 将 undo log 放入列表中,以供之后的 purge(pai rui chi) 线程使用;
  • 判断 undo log 所在的页能否重用,如果可以重用,则分配给下个事务使用;
  • 事务提交后,不能马上删除 undo log 及 undo log 所在的页,这是因为还有其他事务需要通过 undo log 来得到行记录之前的版本,故事务提交将 undo log 放入一个链表中,是否可以最终删除 undo log 及 undo log 所在页由 purge 线程来判断。

当事务提交时,先将 undo log 放入链表中,判断 undo 页的使用空间是否小于 3/4(表示 undo log 可否被重用)。

之后新的undo log 记录在当前的 undo log 的后面,由于存放 undo log 的列表是以记录进行组织的,undo log 可能存放着不同事务的 undo log。

因此,prege 操作需要设计磁盘的离散读取操作,这个过程很缓慢,可以通过设置 purge 线程的个数来提升回收速度。

总结

在 MySQL 中 ,Undo log 回滚日志是数据库事务的重要组成部分,在事务执行变更操作之前先将相反的操作写入 Undo log ,当事务回滚、或数据库崩溃时,通过记录事务执行过程中的旧值,实现对数据库修改的撤销回退,从而确保数据的一致性和可靠性,Undo log 也是实现多版本控制( MVCC )的基础。

通过本文,我们掌握了 Undo log 回滚日志的概念、原理以及在事务中的流程等,可以帮助大家进一步理解、正确应用 Undo log 。

建议收藏备用,划走就找不到啦。

如果有用,请顺手给宝妹儿【关注+点赞】下哦,拜谢。

PS.

本文已收录于宝妹儿精编的 2023版《MySQL 大厂高频面试题大全》PDF。

《MySQL 大厂高频面试题大全》一共78页,34000字,图文并茂,长期持续更新。

吃透它,足以应对 MySQL 面试。

6 张图吃透Undo log,MySQL进阶必知必会!

6 张图吃透Undo log,MySQL进阶必知必会!

0 条回复 A文章作者 M管理员
    暂无讨论,说说你的看法吧