千家信息网

MySQL 8.0源码redo log的产生以及用法是怎样的

发表于:2024-11-26 作者:千家信息网编辑
千家信息网最后更新 2024年11月26日,MySQL 8.0源码redo log的产生以及用法是怎样的,很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。最开始了解my
千家信息网最后更新 2024年11月26日MySQL 8.0源码redo log的产生以及用法是怎样的

MySQL 8.0源码redo log的产生以及用法是怎样的,很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。

最开始了解mysql实现的时候,总听到redo log, WAL(write-ahead logging),undo log这些关键词,了解到redo log主要是用于实现事务的持久化的。为了进一步了解redo log,看了下相关代码(源码版本: mysql 8.0.12),这里简单总结下,主要介绍redo log是如何产生,如何落盘,以及最终通知用户的。

由于学习mysql的时间不长,mysql代码也非常庞大,自己看的也只是其中一小部分,文中有理解得不对的地方,欢迎大家纠正指导,共同学习。

redo log的产生

读写事务在执行的过程中,会不断的产生redo log。申请数据页、修改数据页、记录undo log等,都会产生redo log。mysql将用户事务拆分成一个个mtr(mini transaction),redo log最初产生时就是被记录到mtr中的,并伴随着mtr的提交而提交,最终落到硬盘上。

redo log 的提交

mtr在提交时,会将mtr中的redo log写到系统变量log_sys的log buffer中。mysql8.0一个新特性就是redo log提交的无锁化。在8.0以前,各个用户线程都是通过互斥量竞争,串行的写log buffer,因此能保证lsn的顺序无间隔增长。8.0时用户线程可以并发写log buffer,如果某个用户线程写log buffer成功后,就将自己写的lsn以前的log buffer刷盘,则有可能导致其他用户线程写log buffer还没完成就被刷盘。

图一

为了解决这个问题,mysql 8.0引入了Link_buf这个数据结构来避免log buffer的空洞。Link_buf实际是一个定长数组,像滑动窗口一样跟踪log buffer一段区间的写入情况,随着log buffer中写入连续redo log不断向前推进。

Link_buf的数据结构如图:

图二

当用户在log buffer的start_lsn-end_lsn间写下redo log时,会标记Link_buf相应的位置,即将m_link[start_lsn%m_capacity]赋值为为end_lsn-start_lsn。

redo log记录到log buffer的过程如下:

1.首先,各用户线程写redo log时,先根据redo log长度,向系统全局原子变量log_sys.sn获取本次redo log日志的start_lsn, end_lsn。原子变量sn能保证各线程获得的start_lsn-end_lsn区间连续无空洞;

图三

2.用户线程申请到start_lsn-end_lsn区间后,需要先等待到Link_buf推进到自己可以使用的位置。

图四

如图所示,start_lsn0-end_lsn0,start_lsn2-end_lsn2, start_lsn3-end_lsn3为三个用户线程新申请的lsn区间;start_lsn1-end_lsn1对应的区间已经标记到link_buf上;start_lsn3-end_lsn3距离tail太远,需要等待link_buf推进才能使用;

3.写入log buffer后,再将start_lsn->end_lsn的范围标记到link_buf(注意:因为只在start_lsn%capacity的位置标记link_buf,所以即使end_lsn超过(m_tail, m_tail+m_capacity)也不影响);

图五

4.用户线程提交事务时设置事件log_sys.writer_event,触发log_writer线程将日志从redo log buffer写到系统缓存(log_writer线程自己也会轮询link_buf判断是否写入了新的日志);

5.log_writer线程推进m_tail,并将m_tail前的log buffer落盘。

图六

redo log 的落盘及通知

前面简述了redo log是如何提交的,在redo log提交以及落盘时,涉及多个线程,他们的关系如下:

图七

用户线程在读写事务提交时,会产生一些redo log,并随着mtr提交而记录到redo log buffer中,随后用户线程尝试设置writer_event触发log_writer线程写日志,并监听属于自己的flush_events[i]事件;

log_writer线程推进Link_buf.m_tail,将最大连续lsn前的redo log写入系统缓存,并设置flusher_event触发log_flusher线程;

log_flusher线程将已写入系统缓存的日志刷盘,并设置flush_notifier_event触发log_flush_notifier线程通知用户;

log_flush_notifier根据已刷盘的lsn换算出需要触发的事件,通知用户线程。

具体实现时,通过log_sys中的几个成员变量,跟进redo log的写入情况。其中log_sys.recent_writtern.m_tail表示log buffer最大连续范围;log_sys.write_lsn表示写入到系统缓存的位置;log_sys.flushed_to_disk_lsn表示已落盘的位置。各标记的推进过程如下:

图八

通知用户线程

用户提交事务时,会根据innodb_flush_log_at_trx_commit参数,调用log_wait_for_write或log_wait_for_flush,来等待redo log写入到系统缓存或刷到硬盘。用户线程的通知是通过log_sys.flush_events事件数组来实现的,为了避免一次通知的flush_events过多,flush_events会像桶一样划分给不同的用户线程:redo log是以一个个log block划分的,假设log_sys.flush_events数组长度为m,则第n个log block的刷盘,由flush_events[n%m]事件监听。当log buffer的第L1个log block到第L2个log block被刷盘时,会设置L1-L2之间的log block所属的flush_events,从而redo log在L1-L2之间的用户线程都会收到通知。

图九

mysql8.0通过redo log无锁化,解决了用户线程写redo log时竞争锁带来的性能影响。同时将redo log写文件、redo log刷盘从用户线程中剥离出来,抽成单独的线程,用户线程只负责将redo log写入到log buffer,不再关心redo log的落盘细节,只需等待log_writer线程或log_flusher线程的通知。

看完上述内容是否对您有帮助呢?如果还想对相关知识有进一步的了解或阅读更多相关文章,请关注行业资讯频道,感谢您对的支持。

线程 用户 系统 事务 事件 位置 区间 日志 缓存 变量 数据 标记 数组 过程 学习 源码 最大 不断 之间 代码 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 武汉安卓软件开发团队 sql怎样创建学生数据库表 怎么建立技术对标数据库 大学生万方数据库 软件开发有哪些原则 针对每次网络安全审计 远程服务器系统打印问题 北京守灯网络技术有限公司梁浩 蒂森电梯服务器按键说明 软件开发硕士毕业答辩ppt 微信小程序 云服务器 无线传感器网络技术原理答案 等保三级数据库审计记录保存多久 资产管理系统怎么修改数据库 中国知网ei数据库怎么进 梦幻西游特殊服务器 网络安全工程师上下班时间 观网络安全教育有感200字 tranmic软件开发工具 广州小程序软件开发机构 舟山电子网络技术咨询热线 我的世界服务器养老生存 空间站无线网络技术 服务器对外提供了哪些资源 无线传感器网络技术原理答案 数据库新增数据就报错 国产x86服务器报告 数据库性能优化究竟该如何下手 数据库设计工具 2017 wind股票数据库
0