当前位置: 首页 > 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.jsqmd.com/news/979340/

相关文章:

  • 杭州智能称重货架供应商排行:浙江RFID工具柜/浙江RFID智能货架/浙江abs柜/浙江a存b取柜/浙江双面柜/选择指南 - 优质品牌商家
  • 小程序毕设选题推荐:基于SpringBoot+微信小程序诊所预约挂号系统基于springboot+微信小程序的乡镇医院挂号预约系统【附源码、mysql、文档、调试+代码讲解+全bao等】
  • 腹泻评分转计数建模:Poisson与负二项分布实战指南
  • 2026年工业执行器厂家选购指南:电动夹爪、电动推杆、伺服电缸、定制执行器、自动化核心部件、精密驱动组件厂家选择指南,产能、工艺、品控三维度权威解析 - 海棠依旧大
  • GPT-4参数量与激活率真相:1.8万亿不是体积,2%不是固定值
  • 强化学习中的‘记忆宫殿’:深入剖析PER经验回放的数据结构与采样策略
  • PCA降维后数据‘镜像’了?用sklearn和自实现代码对比鸢尾花数据可视化,揭秘差异原因与注意事项
  • 西安黄金回收市场品牌服务深度解析 - 润富黄金回收
  • 别再乱改配置文件了!Jenkins端口修改的正确姿势(systemctl reload是关键)
  • TPU 3Sin3Xor方案:实现全占空比三相正弦波PWM的硬件协同设计
  • 物理增强神经网络DDCCNet革新量子化学计算
  • 咸阳黄金回收市场盘点 2026年6月六大正规渠道实测 - 润富黄金回收
  • 粉盒植绒加工技术全解析:美妆蛋植绒加工/衣架植绒加工/遮阳板植绒加工/铝管植绒加工/面板植绒加工/香水瓶植绒加工/选择指南 - 优质品牌商家
  • 机器学习监控三把尺:基础设施、数据、业务三层可观测性
  • LLM工程化落地:MLOps与DevOps融合实践指南
  • 别再手动算权重了!用SPSSAU的AHP层次分析法,5分钟搞定旅游决策
  • 从零到一:手把手教你用Docker Compose部署Authelia单点登录(附Traefik配置示例)
  • 别再死记硬背了!用Python代码手把手带你理解A*算法与BFS搜索(附迷宫扫地机器人实战)
  • 告别命令行焦虑:用Rancher 2.5.11的图形界面,5分钟搞定K8s集群与应用部署
  • TPU双通道XOR架构实现SVPWM全占空比与高精度死区控制
  • 别再为TFLite模型下载发愁了!一份完整的离线集成指南(含mnist、yoga_classifier等模型地址整理)
  • 从Type-C回看Micro USB:为什么你的老旧设备接口还这么坚挺?聊聊选型与焊接的‘长寿’秘诀
  • 小程序毕设选题推荐:基于springboot+微信小程序的扶贫助农系统及其小程序的实现产销对接 - 帮扶管理 - 数据追踪【附源码、mysql、文档、调试+代码讲解+全bao等】
  • 桂林七星区余生黄金回收全国连锁门店实测 - 润富黄金回收
  • Kimi K2.5 Agent Swarm架构实战:构建可调试、可扩展的AI协作系统
  • 告别开关损耗!手把手教你用LLC谐振半桥电路设计一个92%+效率的开关电源(附FHA模型分析)
  • 变频器风机品牌怎么选?采购老手的5个靠谱推荐 - 品牌推荐
  • 风电并网搞不懂单位功率因数控制?一个仿真案例讲清它的作用和实现
  • 鲁棒模型开发流程:可落地的生产级ML工作流设计
  • 潜在世界模型:用可视化地形图重构金融风险建模