欢迎光临散文网 会员登陆 & 注册

MySQL redo log恢复原理 | StoneDB技术分享会 #5

2023-08-30 10:20 作者:StoneDB  | 我要投稿


StoneDB开源地址

https://github.com/stoneatom/stonedb

设计:小艾审核:丁奇、李浩责编:宇亭


作者:罗中天

浙江大学-软件工程-在读硕士、StoneDB 内核研发实习生

2023 年 StoneDB 开源之夏项目中选学生

redo log 类型

innodb 的 redo log 是带有逻辑意义的物理日志:物理指的是 redo log 是针对某一个页来说的,每条 redo log 都会有 Type、Space ID、Page Number 等信息,如下图所示;逻辑指的是一条 redo log 中可能描述的不是在页面上的某个偏移量的位置上写入若干个字节的数据,而是描述在页面上插入或者删除一条什么样的记录。
redo log 的通用结构为


Type 的最高位是一个 Single Record Flag 标志位,如果为 1,表示该 redo log 单独构成一个 mtr。
redo log 根据作用的对象,又可以分为作用于 Page 的 redo log,作用于 space 的 redo log 和提供额外信息的 redo log。

作用于 page 的 redo log

大多数的 redo log 属于这一类别,常见的有 MLOG_1BYTE、MLOG_2BYTES、MLOG_4BYTES、MLOG_8BYTES、MLOG_REC_INSERT、MLOG_REC_CLUST_DELETE_MARK、MLOG_REC_UPDATE_IN_PLACE 等。其中 MLOG_1BYTE、MLOG_2BYTES、MLOG_4BYTES、MLOG_8BYTES 描述了在页面的某个偏移量处写入若干个字节的数据;MLOG_REC_INSERT 描述了在页面上插入一条记录;MLOG_REC_CLUST_DELETE_MARK 描述了在聚簇索引的页面上删除一条记录(用户线程删除的操作只会打 delete 标记,物理删除的操作由 purge 线程来做);MLOG_REC_UPDATE_IN_PLACE 描述了在聚簇索引的页面上原地更新一条记录(即修改的是非索引列的字段,二级索引上的更新不会产生该条日志,因为二级索引上的记录没有版本链,所以更新操作产生的 redo log 为 MLOG_REC_CLUST_DELETE_MARK + MLOG_REC_INSERT)。

MLOG_REC_INSERT

MLOG_REC_INSERT 类型的 redo log body 部分的格式为


可见,MLOG_REC_INSERT 类型的 redo log 进行了前缀压缩

MLOG_REC_CLUST_DELETE_MARK


MLOG_REC_UPDATE_IN_PLACE


作用于 space 的 redo log

这类 redo log 描述的是针对一个 space 文件的修改,由于这类文件不是 write ahead 的,而是在文件操作后才记录的,所以在恢复的过程中只会对于文件的状态做一些检查。这类 rede log 不是本文的重点,在后续不再赘述。

提供额外信息的 redo log

这一类的 redo log 主要指的是 MLOG_MULTI_REC_END,只由一个字节的 Type 构成,用于标识一个 mini transaction(简称 mtr)的结尾。

recovery 原理

innodb 的 recovery 从 innodb 启动的时候开始执行,大概流程如下:
1、从 ib_logfile 文件的 header 中找到 checkpoint lsn,作为 recovery 的起点
2、每次从 ib_logfile 文件中读取 64KB 的 redo log 到内存中
3、将每个 log block 的 header 和 trail 去掉后,拼出一份连续的日志
4、以 mtr 为单位进行解析
4.1、判断 MLOG_SINGLE_REC_FLAG 标志位,如果一个 mtr 只由单条日志构成,直接解析后放入哈希表;
4.2、如果一个 mtr 由多条日志构成,需要先找到 MLOG_MULTI_REC_END 类型的日志,确定 mtr 的终点,并加入缓存中,然后将缓存中所有的日志都放入哈希表中
5、将哈希表中的 redo log 进行重放
note:这里不直接在解析的时候回放,而是插入哈希表中回放的好处是:可能会有很多 redo log 作用在同一个 page 上,将这些 redo log 使用一次 IO 进行重放,可以加快重放的速度。该哈希表包括两层,第一层以 space_id 为 key,第二层以 page_no 为 key。
调用栈如下所示(下面的源码基于 MySQL8.0.30 版本)


下面对从 recv_recovery_begin 开始的流程进行详细阐述,在解析 redo log 的时候以解析 MLOG_REC_INSERT 类型的 redo log 为例进行分析。为了突出主干,对代码做了简化。
innodb 将解析和重放的逻辑是写在一起的,当传入的 block 为空时,只解析不重放,当传入的 block 非空时,解析并且重放。

recv_recovery_begin

该函数负责循环从 ib_logfile 文件中读取 64KB 的 redo log 到内存中进行解析,并放入哈希表中


recv_read_log_seg

该函数负责从 ib_logfile 文件中读取 64KB 的 redo log 到内存中。


recv_scan_log_recs

该函数先将每个 log block 的 header 和 trail 去掉后,拼出一份连续的日志,然后以 mtr 为单位进行解析


recv_parse_log_recs

该函数判断 MLOG_SINGLE_REC_FLAG 标志位,根据一个 mtr 是由一条日志组成还是多条日志组成,分开处理。


recv_single_rec

单条 redo log 构成的 mtr 的解析,将单条 redo log 解析后插入到哈希表中。


recv_multi_rec

多条 redo log 构成的 mtr 的解析。
先确定 mtr 的重点,并将解析好的 redo log 加入缓存中,遍历该 mtr 中所有的 redo log,从缓存中取出后插入到哈希表中。


recv_parse_log_rec

该函数负责对单条 redo log 日志进行解析,先解析 Type、Space ID、Page Number,再解析 body


mlog_parse_initial_log_record

该函数负责解析 Type、Space ID、Page Number


recv_parse_or_apply_log_rec_body

该函数负责解析 body,枚举所有的 type 类型,分别进行处理。
这里以 MLOG_REC_INSERT 的日志为例,会先解析字段数量、主键数量、字段长度等信息,构建出索引字典,然后解析剩余的部分,构建出完整的记录,最后插入对应的页中。


mlog_parse_index

该函数负责解析字段的数量,主键的数量和每个字段的长度,构建索引字典


parse_index_fields

该函数负责解析每个字段的长度,填充索引的 field 列表


page_cur_parse_insert_rec

由于 MLOG_REC_INSERT 类型的 redo log 里做了压缩,只记录了和上一条记录不一样的部分,所以需要先解析出上一条记录在页面中的偏移量、待插入记录和上一条记录第一个不相同的字节 mismatch_index 和待插入记录从 mismatch_index 开始的记录长度 eng_seg_len,然后定位到上一条记录,取出前 mismatch_index 个字节,并从 redo log 中解析出待插入记录从 mismatch_index 开始的部分,那么待插入记录就是两部分拼起来,最后插入到 B+树中。


总结

这篇文章我们介绍了 redo log 的分类,不同种类的 redo log 的结构,并且分析了 redo log 在恢复时的流程相关的源码,欢迎大家关注StoneDB的开源代码。


StoneDB 介绍
StoneDB 是石原子科技自主设计研发的国内首款完全兼容于 MySQL 生态的开源 一体化实时 HTAP 数据库产品,具备行列混存、智能索引等核心特性,为 MySQL 数据库提供在线数据实时就近分析服务,能够高效解决 MySQL 数据库在分析型应用场景中面临的能力问题。同时,StoneDB 使用多存储引擎架构的设计,事务引擎具有数据强一致特性,具备完整的事务并发处理能力,使得 StoneDB 可以替代 MySQL 数据库满足在线事务处理场景的需求,使用 MySQL 的用户,通过 StoneDB 可以实现 TP+AP 混合负载,分析性能提升 10 倍以上显著提升,不需要进行数据迁移,也无需与其他 AP 集成,弥补 MySQL 分析领域的空白。


加入StoneDB社区

Github:https://github.com/stoneatom/stonedb

Gitee:https://gitee.com/StoneDB/stonedb

社区官网:https://stonedb.io/

哔哩哔哩:https://space.bilibili.com/1154290084

Twitter:https://twitter.com/StoneDataBase

Linkedin:https://www.linkedin.com/in/stonedb/


加入微信群:添加社区助理-小石侠;加入钉钉群:扫描下方钉钉群二维码。



MySQL redo log恢复原理 | StoneDB技术分享会 #5的评论 (共 条)

分享到微博请遵守国家法律