MySQL 8.0 redo log的深入解析

 更新时间:2021年03月19日 10:08:45   作者:brightdeng@DBA  
这篇文章主要介绍了MySQL 8.0 redo log的深入解析,帮助大家更好的理解和学习使用MySQL数据库,感兴趣的朋友可以了解下

前言

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

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线程的通知。

以上就是MySQL 8.0 redo log的深入解析的详细内容,更多关于MySQL 8.0 redo log的资料请关注脚本之家其它相关文章!

相关文章

  • Canal进行MySQL到MySQL数据库全量+增量同步踩坑指南

    Canal进行MySQL到MySQL数据库全量+增量同步踩坑指南

    这篇文章主要介绍了使用Canal作为迁移工具,将数据库从A服务器迁移至B服务器,为了尽量减少迁移导致的停机时间,考虑使用全量迁移+增量同步的方式
    2023-10-10
  • 解决mysql ERROR 1017:Can''t find file: ''/xxx.frm'' 错误

    解决mysql ERROR 1017:Can''t find file: ''/xxx.frm'' 错误

    如果重启服务器前没有关闭mysql,MySql的MyiSAM表很有可能会出现 ERROR #1017 :Can't find file: '/xxx.frm' 的错误
    2011-08-08
  • MySQL 清除表空间碎片的实例详解

    MySQL 清除表空间碎片的实例详解

    这篇文章主要介绍了MySQL 清除表空间碎片的实例详解的相关资料,希望通过本文能帮助到大家,需要的朋友可以参考下
    2017-10-10
  • 使用Rotate Master实现MySQL 多主复制的实现方法

    使用Rotate Master实现MySQL 多主复制的实现方法

    众所周知,MySQL只支持一对多的主从复制,而不支持多主(multi-master)复制
    2012-05-05
  • MySQL中的间隙锁代码示例讲解

    MySQL中的间隙锁代码示例讲解

    锁是mysql提供的一种保证不同事务读写隔离的重要措施,通过锁机制可以有效提升决多线程下并发处理事务能力,不同的锁划分对应着不同的使用场景,本文来深入探讨一下mysql的另一种容易被忽视的锁,即间隙锁,以及与之相关的相关问题,需要的朋友可以参考下
    2023-08-08
  • MySQL索引失效的典型案例

    MySQL索引失效的典型案例

    索引在我们使用MySQL数据库时可以极大的提高查询效率,然而,有时候因为使用上的一些瑕疵就会导致索引的失效,无法达到我们使用索引的预期效果,今天介绍一种MySQL中几种常见的索引失效的原因,可以在以后的工作中尽可能避免因索引失效带来的坑。
    2021-06-06
  • MySQL 中定义和使用变量的方法

    MySQL 中定义和使用变量的方法

    MySQL 提供了多种类型的变量,以适应不同的应用场景,用户定义的变量适用于简单的会话内数据传递,局部变量适合在复杂的存储过程中使用,而会话变量则用于调整和优化数据库会话的行为,这篇文章主要介绍了MySQL 中定义和使用变量,需要的朋友可以参考下
    2024-04-04
  • Mysql 索引从入门到精通(从原理到实践)

    Mysql 索引从入门到精通(从原理到实践)

    本文介绍MySQL索引深度解析:从原理到实践,本文涵盖索引基础概念、类型、底层原理及管理策略,结合实例代码给大家介绍的非常详细,感兴趣的朋友跟随小编一起看看吧
    2025-10-10
  • Navicat自动备份MySQL数据的流程步骤

    Navicat自动备份MySQL数据的流程步骤

    对于从事IT开发的工程师,数据备份我想大家并不陌生,这件工程太重要了!对于比较重要的数据,我们希望能定期备份,每天备份1次或多次,或者是每周备份1次或多次,所以本文给大家介绍了Navicat自动备份MySQL数据的流程步骤,需要的朋友可以参考下
    2024-12-12
  • 基于MySql的扩展功能生成全局ID

    基于MySql的扩展功能生成全局ID

    本文借用 MySQL的扩展功能 REPLACE INTO 来生成全局id,REPLACE INTO和INSERT的功能一样,但是当使用REPLACE INTO插入新数据行时,如果新插入的行的主键或唯一键(UNIQUE Key)已有的行重复时,已有的行会先被删除,然后再将新数据行插入
    2015-12-12

最新评论