当前位置: 首页 > news >正文

【MySQL高阶】23.重做日志(1)

文章目录

  • 6. InnoDB 磁盘文件
    • 6.9 重做日志 - Redo Log
      • 6.9.5 什么是Mini-Transaction?
        • 6.9.5.1 DML操作会对数据页产生什么样的影响?
        • 6.9.5.2 在记录RedoLog时服务器崩溃了导致日志不完整怎么办?
        • 6.9.5.3 Mini-Transaction的定义
        • 6.9.5.4 如何标识一组RedoLog属于同一个MTR?
        • 6.9.5.5 如果一个MTR中只有一条日志是否可以优化?
        • 6.9.5.6 事务与Mini-Transaction是什么关系?
      • 6.9.6 RedoLog是如何写入缓冲区的?
        • 6.9.6.1 用来组织RedoLog的数据结构是什么?
        • 6.9.6.2 Log Block Header和Log Block Trailer都记录了哪些信息?
        • 6.9.6.3 Redo Log Block在Log Buffer中是如何组织的?
        • 6.9.6.4 从日志缓冲区写RedoLog时从内存中的哪个地址开始写?
        • 6.9.6.5 不同的事务在并发执行时如何记录RedoLog?
      • 6.9.7 Redo Log的刷盘时机?
        • 6.9.7.1 刷盘策略可以进行配置吗?
        • 6.9.7.2 不同的刷盘策略有什么影响?

6. InnoDB 磁盘文件

6.9 重做日志 - Redo Log

6.9.5 什么是Mini-Transaction?

6.9.5.1 DML操作会对数据页产生什么样的影响?

以一个Insert操作为例,对数据页的影响一般分为两种情况:

如果写入记录所在的数据页空间充足,足够存储一条将要写入的记录,那么就可以直接写入,如下图所示:

如果写入的数据页空间不充足,无法放下这条记录,由于在数据页中真实数据是按主键顺序排列的,那么就要新建一个数据页,对原来的数据进行调整,把一部分数据复制到新的数据页中,以便在目标数据页上留出足够的空间来保存即将写入的记录,此时对应的示意图如下所示:

因为新插入的数据按照主键顺序排列的,那么就要新建一个数据页,对原来的数据进行调整

通过以上两种情况下插入一条记录的分析可以看出,当数据页空间充足的情况下可以直接写入数据,并记录一条对应RedoLog即可

当数据页空间不充足无法放下这条记录的情况下,会创建一个新数据页,同时还有数据的复制和写入,索引树非叶子节点上修改,在实际的执行过程中还有对表空间中段、区中统计信息的修改等等,这意味一个简单的Insert操作有会产生很多条RedoLog


6.9.5.2 在记录RedoLog时服务器崩溃了导致日志不完整怎么办?

那么这时有一个问题需要考虑,试想一下如果执行这一系统操作的时候,RedoLog只记录了一半(不完整的日志)服务器就崩溃了,那么当服务器重启的时候如果按照RedoLog进行恢复,得到的结果肯定是错误的。

所以在记录RedoLog的时候要保证一个DML所对应的一系列日志必须是完整的才可以执行恢复操作,否则就不执行恢复。

那么怎么才能标记DML操作对应的日志是完整的呢?


6.9.5.3 Mini-Transaction的定义
  • Mini-Transaction就是针对以上的操作过程定义的概念,也就是说把记录一个DML操作的过程称为一个Mini-Transaction,简称MTR,一个所谓的MTR包含一个DML操作产生的一组完整日志,在进行崩溃恢复时这一组RedoLog做为一个不可分割的整体(要么全执行,要么全不执行)。
  • 这里所说的不可分割的组是MySQL中定义的,常见的有:
    • 向聚簇索引对应B+树的页面中插入一条记录时产生的RedoLog不可分割;
    • 向某个二级索引对应B+树的页面中插入一条记录时产生的RedoLog不可分割;
    • 还有其他的一些对页面的访问操作时产生的RedoLog不可分割。
  • 每条语句根据具体的执行情况可能会产生多个MTR

总结:

Mini-TransactionMySQL内部对底层数据页的一个原子操作,包含一个DML操作产生的一组完整日志,保证数据库异常恢复时数据页中数据的一致性。


6.9.5.4 如何标识一组RedoLog属于同一个MTR?

在执行DML操作的过程中,每一个对数据页的修改都会记录一条RedoLog,这些日志会被顺序记录下来,并在这组日志的最后加一条特殊的日志标识作为一个MRT的结尾。

这条特殊的日志结构非常简单,只有一个TYPE字段,类型为MLOG_MULTI_REC_END = 31,也就是日志分类中的提供额外信息的日志类型,一个MTR对应的日志组,如下图所示:


6.9.5.5 如果一个MTR中只有一条日志是否可以优化?
  • 当然可以,如果一个MTR只有一条日志,直接在这条日志后加一个类型为MLOG_MULTI_REC_END = 31的标识可以做为MTR的结尾,但这样做有点浪费空间;

  • InnoDB为了尽可能的节省空间,在MTR只有一条日志的情况下,做了一个优化。通过上面的介绍了解了日志类型虽然很多,但也只有几十种,而用来表示日志类型的TYPE字段长度为1BTYE, 而这1BTYE中只用7个比特位,代表整数127,就完全可以表示所有的日志类型,与是省出来一个比特位就可以用来表示当前MTR包含一条还是一组RedoLog,也就是说如果TYPE字段的第一个比特位为1,表示MTR只包含一条RedoLog,为0表示MTR包含一组RedoLog,如下图所示:


6.9.5.6 事务与Mini-Transaction是什么关系?

Mini-Transaction是包含的是一个DML操作对应的一组RedoLog,而一个事务中可能会包含多个DML操作,所以一个事务中包含一个或多个SQL语句,一个SQL语句包含一个或多个MTR,一个MTR包含一条或多条RedoLog,他们之间的关系如下图所示:


6.9.6 RedoLog是如何写入缓冲区的?

6.9.6.1 用来组织RedoLog的数据结构是什么?

用来组织RedoLog的数据结构是Redo页,页的大小是512B,也可以称为一个Redo Log Block,这个大小刚好对应磁盘上一个扇区,当日志写入磁盘时可以保证连续性,Redo Log Block的示意图如下所示:

在一个Redo Log Block中,包含用来存储管理信息的块头Log Block Header(占12Byte)和块尾Log Block Trailer(占4Byte),其他的空间是真正用来存储日志的区域Log Block Body(占496B)


6.9.6.2 Log Block Header和Log Block Trailer都记录了哪些信息?

Log Block HeaderLog Block Trailer包含的信息如下图所示:

  • Log Block Header

    1. LOG_BLOCK_HDR_NOBlock的唯一标识,是一个大于0的值,取值范围1~0x40000000UL,而0x40000000UL对应的整数是10737418241GB,也就是说InnoDB最多能够生成1GB个日志块,每个日志块为512B,所以InnoDB允许维护日志的最大容量为512GB,在后面介绍配置日志相关的选项时,关于日志容量的大小就是以此为依据;
    2. LOG_BLOCK_HDR_DATA_LEN:表示Block中已经使用了多少字节,由于块头占用了12B的空间,所以初始值为12,当Log Block Body被全部写满时那么这个值就是512
    3. LOG_BLOCK_FIRST_REC_GROUP:如果一个MTR会生产多条redo日志记录,这些日志记录被称之为一个redo日志记录组,LOG_BLOCK_FIRST_REC_GROUP代表该Block中第一个MTR中第一条日志的偏移量。
    4. LOG_BLOCK_CHECKPOINT_NO:表示检查点的编号,关于检查点后面会详细详解
  • Log Block Trailer

    • LOG_BLOCK_CHECKSUM:表示Block的校验和,用于正确性校验。

6.9.6.3 Redo Log Block在Log Buffer中是如何组织的?

在内存中RedoLog存储在日志缓冲区(Log Buffer)中,日志缓冲区是服务器启动时向操作系统申请的一片连续的内存区域,并被划分成若干个连续的Redo Log Block,用来存储即将要写入磁盘日志文件的数据,如下图所示:

日志缓冲区大小可以通过系统变量innodb_log_buffer_size指定,默认大小为16MB,取值范围1048576(1MB) ~ 4294967295(4GB)

# 查看当前Log Buffer的大小 mysql> show variables like 'innodb_log_buffer_size'; +------------------------+----------+ | Variable_name | Value | +------------------------+----------+ | innodb_log_buffer_size | 16777216 | +------------------------+----------+ 1 row in set (0.00 sec) # 设置Log Buffer的大小 mysql> set persist innodb_log_buffer_size =33554432; Query OK, 0 rows affected (0.03 sec) mysql>

向日志缓冲区中写入日志是一个顺序写入的过程,也就是从缓冲区的第一个Redo Log BlockLog Block Body开始依次向后写,一个block的空间用完之后在写下一个block

那么有一个首先要解决的问题,当有一个日志需要写入缓冲区的时候,应该往哪个block中的位置写呢?


6.9.6.4 从日志缓冲区写RedoLog时从内存中的哪个地址开始写?

InnoDB的提供了一个名为buf_free的全局变量,该变量表示后续写入日志在Log Buffer中的起始位置。

如图所示:


6.9.6.5 不同的事务在并发执行时如何记录RedoLog?
  • 通过前面的介绍了解到,InnoDBMTR为单位记录RedoLog,一个事务中包含多个MTR,一个MTR包含多条RedoLog,这些RedoLog是一个不可分割的日志组;
  • 一个事务在执行过程中并不是每生成一条RedoLog就写入到Log Buffer中,而是把生成的RedoLog先缓存在内存的一个区域中,当一个MTR执行完成后把这组日志一起复制到Log Buffer
  • 假设有两个事务T1, T2并发执行,每个事务中都包含2MRT,即事务T1包含mtr_t1_1mtr_t1_2T2包含mtr_t2_1mtr_t2_2,如下图所示:

  • 在并发环境下不同事务中的MTR是交替执行的,当MTR执行完成之后对应生成的RedoLog会被写入Log Buffer,所以在Log Buffer中日志的写入形式如下图所示:

  • 需要说明一点,不同的MTR产生的日志组占用的存储空间可能不一样,有的MTR产生的日志很少,有的MTR产生的日志量非常多。

总结:

  • RedoLog在内存中用Redo页进行组织,称为Redo Log Block,每个Redo Log Block大小固定为512B,对应磁盘上一个扇区,日志被顺序安排在Log Block Body中;
  • Log Buffer中多个Redo Log Block顺序排列,Redo Log Block的个数由Log Buffer的大小决定;
  • 当执行事务时,不同的语句对应不同的数据库操作,一条SQL语句可能包含多个MTR,一个MTR包含多条RedoLogMTR中的多条日志称为一个日志组,写入Log Buffer的日志是以MTR对应的日志组为一个单位,这组日志不可分割。

6.9.7 Redo Log的刷盘时机?

当一个MTR执行完成后,RedoLog会被写入Log Buffer,而Log Buffer大小是有限的,并且这些记录日志的目的是为了服务器崩溃后的数据恢复,在内存中保存也不安全,所以在把它们刷到磁盘上进行保存

总结:

  • InnoDB在以下情况会把RedoLog刷到磁盘:
    • Log Buffer空间不足时:Log Buffer大小是有限的,可以通过系统变量innodb_log_buffer_size设置,如果当前Log Buffer中的RedoLog占用了Log Buffer总容量一半左右会触发刷盘;
    • 事务提交前,事务对应的日志必须落盘
    • 当事务提交时,事务中对应的MTR已经完整的记录在了Log Buffer中,在数据真正落盘之前,需要把对应的RedoLog刷新到磁盘;
    • 后台线程定时刷盘:后台的Master Thread线程,大约每秒都会把Log Buffer中的RedoLog刷新到磁盘;
    • 正常关闭服务器时:在服务关闭之前会把会把Log Buffer中的RedoLog刷新到磁盘;
    • 做检查点(checkpoint)操作时:关于checkpoint后面会详细介绍

6.9.7.1 刷盘策略可以进行配置吗?
  • 可以
  • 日志缓冲区的内容定期刷新到磁盘,可以通过系统变量Innodb_flush_log_at_timeout=N设置,N默认为1,单位为秒;
  • 通过设置系统变量innodb_flush_log_at_trx_commit设置写入和刷盘策略,默认值为1
    • 0:日志每秒写入系统缓冲区并刷新到磁盘,未写入系统缓冲区的事务日志可能会在MYSQL崩溃时丢失;(秒为单位)
    • 1:日志在每次事务提交时写入系统缓冲区并刷新到磁盘;(事务为单位)
    • 2:日志在每次事务提交后写入系统缓冲区并每秒一次刷新到磁盘,未刷新到磁盘的日志可能在系统崩溃时丢失。
  • 如果启用二进制日志且设置sync_binlog = 1时,则必须设置innodb_flush_log_at_trx_commit = 1

6.9.7.2 不同的刷盘策略有什么影响?

首先看一下Log Buffer、操作系统缓存和磁盘中日志文件的关系,如图所示:

这里主要讨论系统变量innodb_flush_log_at_trx_commit对应的几种情况:

  1. 值为0时:表示日志每秒写入操作系统缓存并刷新到磁盘,如果MySQL崩溃,那么在一秒内没有写入操作系统缓存的Redo Log将会丢失;
  2. 值为2时:日志在每次事务提交后写入系统缓冲区并每秒一次刷新到磁盘,此时已提交的事务Redo Log全部都写入了操作系统缓存,MySQL无论是否崩溃,Redo Log都会以指定的时间刷新到磁盘,但是如果服务器崩溃或断电,将会导致操作系统缓存中的Redo Log丢失;
  3. 值为1时:日志在每次事务提交时写入系统缓冲区并刷新到磁盘,此时Redo LogLog Buffer中写入操作系统缓存并立即刷新到磁盘,从而尽可能的保证日志的完整性,推荐使用。
http://www.rkmt.cn/news/1491065.html

相关文章:

  • 强化学习中的‘记忆宫殿’:深入剖析PER经验回放的数据结构与采样策略
  • 2026年工业执行器厂家选购指南:电动夹爪、电动推杆、伺服电缸、定制执行器、自动化核心部件、精密驱动组件厂家选择指南,产能、工艺、品控三维度权威解析 - 海棠依旧大
  • 杭州智能称重货架供应商排行:浙江RFID工具柜/浙江RFID智能货架/浙江abs柜/浙江a存b取柜/浙江双面柜/选择指南 - 优质品牌商家
  • 西安黄金回收市场品牌服务深度解析 - 润富黄金回收
  • LLM工程化落地:MLOps与DevOps融合实践指南
  • 变频器风机品牌怎么选?采购老手的5个靠谱推荐 - 品牌推荐
  • 从Type-C回看Micro USB:为什么你的老旧设备接口还这么坚挺?聊聊选型与焊接的‘长寿’秘诀
  • 告别开关损耗!手把手教你用LLC谐振半桥电路设计一个92%+效率的开关电源(附FHA模型分析)
  • 风电并网搞不懂单位功率因数控制?一个仿真案例讲清它的作用和实现
  • 从MPC857T到MPC885嵌入式平台升级:硬件迁移与驱动适配实战指南
  • 2026年浙江宠物护理技校TOP排行与择校参考:浙江数字媒体技校/浙江新能源学校/浙江新能源技校/浙江无人机学校/选择指南 - 优质品牌商家
  • 数据科学数学实战指南:从pandas到梯度下降的三层能力图谱
  • 梯度自适应拉盖尔格型滤波器MATLAB工程包(含仿真图、说明文档与Python接口)
  • 杭州青少年厌学干预技术解析:杭州孩子心理辅导学校、杭州家庭教育学校、杭州心理咨询学校、杭州心理辅导学校、杭州戒网瘾学校选择指南 - 优质品牌商家
  • AI工程师必备:如何用Newsletter构建技术决策雷达
  • 2026年6月北京老房改造装修公司推荐:五大排名老房翻新评测专业价格 - 品牌推荐
  • STM32烧录报错No target connected?别急着换仿真器,先检查这个HAL库里的‘隐藏开关’
  • Spring Boot微服务日志收集实战:用Filebeat+Logstash+ES 7.13.0搭建ELK监控(含多行日志合并配置)
  • InstaGAN自定义数据集:打造专属的图像翻译应用
  • 从URDF到Python仿真:用Robotics Toolbox快速验证你的ROS机器人模型
  • 磁力链接转换种子文件的终极指南:Magnet2Torrent完整教程
  • C#写的录屏工具源码,能同时录屏幕、系统声和麦克风并实时混音
  • SpringBoot项目实战:用阿里云短信服务+Redis搞定登录验证码(防刷版)
  • DeiT vs 传统CNN:1.3GMACs算力下的图像分类性能终极对比指南
  • 从Freechess到WintrChess:开源国际象棋分析工具演进路线图分析
  • 【保定黄金回收哪家好 六大品牌机构2026年6月实测盘点】 - 润富黄金回收
  • 7.5元的RC522读卡器能干啥?我用Arduino Uno做了一个门禁卡复制器(附完整接线图与代码)
  • 重庆商用厨房设备技术解析:专业厂家选型参考 - 优质品牌商家
  • 冶炼厂污水处理压滤机技术选型要点与规格适配:压滤机定制/压滤机滤布/压滤机滤板/压滤机配件/厢式压滤机厂家/厢式压滤机推荐/选择指南 - 优质品牌商家
  • 如何构建高性能C++ Web应用:Wt框架架构设计与性能优化实践