Redo 日志无锁化设计并发写入 log buffer

本文深入探讨了MySQL 8.0中Redo日志的并发写入机制,指出在新版本中实现了无锁化设计,允许多个用户线程同时写入log buffer,显著提升了效率。文章通过实例详细介绍了Redo日志的产生、写入、日志文件刷盘的各个阶段,并分析了如何确保日志的连续性和并发安全性,最后总结了整个流程的关键点。
摘要由CSDN通过智能技术生成

本文由作者公众号一树一溪首发,欢迎关注。

对于这样的剧情,想必大家不会陌生:美国大片中拯救世界的英雄,平时看起来跟普通人没啥区别,甚至还可能会有点让人看不上。

但是,关键时刻,却能爆发出惊人能量,挽狂澜于既倒,扶大厦于将倾,拯救世界于危难之中。

今天我们要聊的主角:Redo 日志,也是这样的平民英雄。

本来 InnoDB 接收到插入、修改、删除这样的 DML 语句,以及创建表 & 索引、修改表结构这样的 DDL 语句,修改 Buffer Pool 中的数据页之后就完事了。

因为要保证数据不丢失,事情就变的复杂了,修改了数据页不算完,还要生成 Redo 日志,生成了也不算完,还要把它写入 Redo 日志文件

为了方便描述,本文后面会把 Redo 日志文件简称为日志文件

通过以上描述,相信大家能够发现,生成 Redo 日志并写入日志文件,显然是额外操作,会额外消耗资源。

不惜额外消耗宝贵的服务器资源都要保存下来的东西,肯定不能是个绣花枕头,那这个有用的枕头什么时候能派上用场呢?

当然是服务器累了想小憩一下(突然崩溃)的时候了 _

服务器也不容易,谁还没有个突然崩溃的时候呢?

说了这么多,是时候确定 Redo 日志的历史地位了:Redo 日志,在太平日子里,不但是个鸡肋,更是个累赘,但是,别把它不当英雄,关键时刻还得靠它拯救数据库

饭前甜点到此为止,接下来是正餐。

本文内容基于 MySQL 8.0.29 源码。

目录


正文

1. 概述

MySQL 8.0 以前,Redo 日志是串行写入 log buffer 的,多个用户线程想要同时往 log buffer 里写日志,那是不行的,必须排队等待(获取互斥锁),拿到互斥锁之后,才能往 log buffer 里写日志。

MySQL 8.0 中,串行写入变为并行写入,log buffer 由乡间小道变成了单向 8 车道的高速公路,多个用户线程可以同时往 log buffer 里写入 Redo 日志,效率大大提升。

Redo 日志从产生到刷盘,一共会经历 4 个阶段(产生、写 log buffer、写日志文件、刷盘),本文会用 4 个小节分别介绍这 4 个阶段。

2. Redo 日志产生

以一条非常简单的插入语句为例,这个语句包含自增列,并且只插入一条记录,我们假设插入过程中不会造成索引页分裂,也不会产生溢出页。

不考虑 Undo 日志产生的 Redo 日志,这样一条 SQL 语句会包含 2 条 Redo 日志(这 2 条日志会形成一个日志组):

  • 一条日志中保存着表中自增列的最大值(MySQL 8.0 把自增列的值持久化了)。
  • 另一条日志中保存着插入记录各字段的值。

每条日志中还有可能会包含 InnoDB 需要的其它信息。

插入记录的过程中,会先产生一条 Redo 日志用于记录表中自增列的最大值,然后插入记录,再产生另一条 Redo 日志。

Redo 日志并不会每产生一条就马上写入 log buffer,而是一组 Redo 日志攒到一起往 log buffer 里写。

问题来了,产生了一条 Redo 日志不能马上写入 log buffer,那怎么办?

那就需要有一个地方临时存放日志组中不同时间点产生的日志了,这个地方就是 mtr 中的 m_log 链表

m_log 链表是由一个一个 block 组成的链表,block 大小为 512 字节,每产生一条日志,就追加到 m_log 的 block 中,如果一个 block 写满了,就再申请一个 block 接着写。

那 mtr 又是个啥?

mtr 是 Mini-Transaction 的缩写,是一组不可分隔的操作组成的一个整体,就像前面插入语句的例子中,保存表中自增列的最大值插入记录就是一组不可分隔的操作,必须放入一个 mtr。

两个操作放入一个 mtr,它们的日志也就放在同一个 mtr 中了。这样就能保证两个操作产生的 Redo 日志一起写入 log buffer 和日志文件中。

mtr 的用途可不止打包一组 Redo 日志这么简单,它还会对 SQL 执行过程中 mtr 需要访问的 Buffer Pool 中的页加锁、修改页中的数据、释放锁,本文我们只介绍 Redo 日志,对于 mtr 就不再展开了。

还有一个概念需要解释一下,日志组就是一个 mtr 中的所有日志。

3. 写入 log buffer

mtr 中一组不可分隔的操作都完成之后,就该提交了,mtr 提交过程中要干的第一件事就是把它里面临时存放的一组 Redo 日志写入到 log buffer 中。

一个事务中可能会包含多个 mtr,mtr 的提交和事务的提交不是一个概念,不要混淆。

前面说到在 MySQL 8.0 中,往 log buffer 里写日志不需要排队等待(获取互斥锁),多个用户线程可以同时写入。

这个无锁化设计是通过在 log buffer 中为每个 mtr 中的 Redo 日志预留空间实现的,每个 mtr 都有一段属于自己的空间,各自往自己专属的空间内写入日志,相互之间就不影响了。

用户线程的 mtr 往 log buffer 写 Redo 日志前,会先获取一段序列号。

以当前系统中已产生的最大序列号(SN)作为 start_sn,加上本次要往 log buffer 中写入的 Redo 日志的字节数(len),得到 end_sn(end_sn = start_sn + len)。

start_sn ~ end_sn 就是本次要写入 log buffer 的 Redo 日志的序列号区间。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
redolog、binlog和undolog是数据库中常见的日志类型,它们在数据库的事务处理和恢复过程中起着重要的作用。下面是它们的区别和作用: 1. Redo Log(重做日志): - Redo Log是用于保证事务的持久性和恢复能力的一种日志记录机制。 - 当数据库执行写操作时,会先将数据写入内存中的Buffer Pool,然后再将修改操作记录到Redo Log中。 - Redo Log的作用是在数据库崩溃或者意外断电等情况下,通过重做日志的回放,将未提交的事务重新应用到数据库中,确保数据的一致性和完整性。 2. Binlog(二进制日志): - Binlog是MySQL数据库特有的日志记录机制,用于记录数据库中的所有修改操作。 - Binlog记录了数据库中所有的DDL语句和DML语句,包括对表结构的修改和对数据的增删改操作。 - Binlog的作用是用于数据备份、主从复制和恢复等场景,可以通过回放Binlog来还原数据库到某个特定时间点的状态。 3. Undo Log(撤销日志): - Undo Log是用于实现事务的回滚和MVCC(多版本并发控制)机制的一种日志记录方式。 - 当数据库执行修改操作时,会先将原始数据备份到Undo Log中,然后再进行修改操作。 - Undo Log的作用是在事务回滚或者MVCC读取数据时,通过回滚或者读取Undo Log中的数据,实现数据的一致性和隔离性。 Buffer Pool(缓冲池): - Buffer Pool是数据库中的一个内存区域,用于缓存数据库中的数据页。 - 当数据库执行读操作时,会先在Buffer Pool中查找数据,如果找到则直接返回,如果没有则从磁盘加载到Buffer Pool中。 - Buffer Pool的作用是提高数据库的读取性能,减少磁盘IO操作。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值