背景

MySQL 版本: 8.0.23

数据库系统中关于事务有 4 个重要特性 ACID, 其中 A 代表的原子性: 一个事务必须被视为一个不可分割的最小工作单元,整个事务中的所有操作要么全部提交成功,要么全部失败回滚,对于一个事务来说,不可能只执行其中的一部分操作,这就是事务的原子性. 对于 InnoDB 来说, 针对意外崩溃情况,也需要保证事务满足原子性,即在崩溃前提交的事务需要保证重启后可读, 尚未提交的事务需要正确的回滚.

Redo Log

关于 Redo Log 在之前的文章 InnoDB 的 Redo Log 分析 已经详细介绍过, InnoDB 利用 Redo Log 来记录所有的数据和其他的文件操作. InnoDB 在对应操作的 Redo Log 落盘后就会给用户返回操作成功, 此时对应的数据 Page 可能还在 Buffer Pool 中尚未落盘, 这里可以加快的写入的速度, 但也需要在意外崩溃后能使数据库的数据 Page 恢复到一个正确的状态.

Undo Log

InnoDB 使用 MVCC + Undo Log 来实现不同的事务隔离级别, 在数据库正常的运行时,用户可以通过 Undo Log 来在不同的隔离级别下读取相应正确的数据, 其中在意外崩溃后,InnoDB 需要使用 Undo Log 来回滚尚未提交的事务.

Checkpoint

在 MySQL 8.0 新建了一个独立的线程log_checkpointer来执行 checkpoint 任务, 当 InnoDB 执行一次 checkpoint 时, 会将指定 lsn 位置的数据 Page 刷入磁盘, 这就保证了在此 lsn 之前的数据均以持久化. log_checkpointer在执行 checkpoint 后会写入 checkpoint 信息至ib_logfile0, InnoDB 设计在 offset 512 bytes 和 1536 bytes 轮流写 checkpoint 信息,防止某次写入 checkpoint 失败导致故障恢复无法找到上次的位点.

回滚流程

当 MySQL 启动后,无论之前是否发生 crash 都会尝试进行 recover (recv_recovery_from_checkpoint_start()):

  • 首先读取 checkpoint 信息,找到记录的最新的 checkpoint (recv_find_max_checkpoint()).

*

事务回滚

总结