gball个人知识库
首页
基础组件
基础知识
算法&设计模式
  • 操作手册
  • 数据库
  • 极客时间
  • 每日随笔
  • 学习
  • 面试
  • 心情杂货
  • 实用技巧
  • 友情链接
  • 画图工具 (opens new window)
关于
  • 网盘 (opens new window)
  • 分类
  • 标签
  • 归档
项目
GitHub (opens new window)

ggball

后端界的小学生
首页
基础组件
基础知识
算法&设计模式
  • 操作手册
  • 数据库
  • 极客时间
  • 每日随笔
  • 学习
  • 面试
  • 心情杂货
  • 实用技巧
  • 友情链接
  • 画图工具 (opens new window)
关于
  • 网盘 (opens new window)
  • 分类
  • 标签
  • 归档
项目
GitHub (opens new window)
  • 面试

  • 数据库

    • mysql

      • mysql思维导图
      • 7全文索引
      • mysql导入导出
      • mysql服务
      • mysql基本语句
      • mysql之sql_mode
      • sql函数
      • 每年,每季,每月,每周的最后一天
      • 数据库小笔记
      • 重新认识mysql
      • mysql系统配置与启动选项
      • 字符集和比较规则
      • InnoDB记录结构
      • InnoDB数据页结构
      • B+树索引的由来
      • mysql之InnoDB数据目录结构
      • explain之访问方法
      • EXPLAIN 语句输出的各个列解释
      • mysql之InnoDB的BufferPool
      • mysql之事务
      • redo日志(上)
        • redo日志
          • 复杂 redo 日志类型
          • Mini-Transaction的概念
          • 事务的全貌
          • redo log 写入过程
        • redo log block
          • redo log block组成部分
        • redo日志写入log buffer
      • redo日志(下)
      • MVCC并发管理控制
      • undo log了解
    • pg

    • redis

  • linux

  • node

  • tensorFlow

  • 基础组件

  • 基础知识

  • 算法与设计模式

  • 分布式

  • 疑难杂症

  • go学习之旅

  • 极客时间

  • 知识库
  • 数据库
  • mysql
ggball
2022-03-04

redo日志(上)

# redo日志

背景: 因为事务提交后,数据不会立刻刷入磁盘(1.刷新一个完整的数据页太浪费了2.随机IO刷起来比较慢),而是在合适的时机刷入磁盘,但是为了不让宕机等因素将缓存数据清空,所以需要记录一份事务提交的数据,方便以后还原。

作用: 记录下记录修改的信息(所在表空间,页号,修改信息),系统崩溃了的话,也可以利用redo日志恢复。

过程: 该事务执行过程中产生的 redo 日志刷新到磁盘。

通用组成:

  • type :该条 redo 日志的类型。在 MySQL 5.7.21 这个版本中,设计 InnoDB 的大叔一共为 redo 日志设计了53种不同的类型,稍后会详细介绍不同类型的 redo 日志。
  • space ID :表空间ID。
  • page number :页号。
  • data :该条 redo 日志的具体内容。

image-20220225100731337

类型:根据记录修改的字节(type字段长度)大小分类

  • MLOG_1BYTE ( type 字段对应的十进制数字为 1 ):表示在页面的某个偏移量处写入1个字节的 redo 日志类型。
  • MLOG_2BYTE ( type 字段对应的十进制数字为 2 ):表示在页面的某个偏移量处写入2个字节的 redo 日志类型。
  • MLOG_4BYTE ( type 字段对应的十进制数字为 4 ):表示在页面的某个偏移量处写入4个字节的 redo 日志类型。
  • MLOG_8BYTE ( type 字段对应的十进制数字为 8 ):表示在页面的某个偏移量处写入8个字节的 redo 日志类型。
  • MLOG_WRITE_STRING ( type 字段对应的十进制数字为 30 ):表示在页面的某个偏移量处写入一串数据。

# 复杂 redo 日志类型

如果数据频繁的改动,那是不是对应的redo log也要跟着增加呢,这样岂不是和保存的数据是一个道理了,占用着和她差不多的空间,为了减少空间的消耗,提出了复杂 redo 日志类型。

比如,MLOG_COMP_LIST_START_DELETE(范围删除的开始)和MLOG_COMP_LIST_END_DELETE(范围删除的结束)类型的redo日志

当我们要删除id=1 到id=15之间的日志,按照之前的redo日志的记录方式,是不是要保存15条对应记录的修改,而现在我们可以使用两条redo日志,分别记录范围删除的开头和结尾,这样就大大缩减了redo日志的条数。

执行DDL语句时,存储引擎做的操作有很多,比如插入一条数据,数据页中的page header,page directory要修改,如果页超过容量了,页还需要分裂,目录页和数据页之间的指针也要修改,等等操作。所以我们可以知道把一条记录插入到一个页面时需要更改的地方非常多。看下类型为 MLOG_COMP_REC_INSERT 的 redo 日志的结构(有印象就行)

image-20220225112439998

记住:redo日志会把事务在执行过程中对数据库所做的所有修改都记录下来,在之后系统奔溃重启后可以把事务所做的任何修改都恢复出来。

保证写入redo日志的原子性,特别是插入操作会引起多条redo日志的插入

# Mini-Transaction的概念

一次记录的增删改操作,都会伴随着多条redo日志插入,为了更有效率的插入redo日志,InnoDB的大叔将多条redo日志分为多个分组,每个分组都是不可分割的。

如何确定每个分组是否完整写入成功呢

在每组redo日志中的最后一条 redo 日志后边加上一条特殊类型的 redo 日志,该类型名称为 MLOG_MULTI_REC_END

image-20220301152643956

这样在系统奔溃重启进行恢复时,只有当解析到类型为 MLOG_MULTI_REC_END 的 redo 日志,才认为解析到了一组完整的 redo 日志,才会进行恢复。否则的话直接放弃前边解析到的 redo 日志。(很像网络传输包,判断结束标志位)

# 事务的全貌

image-20220301152932818

# redo log 写入过程

为了让redo log更有效率地写入磁盘,mysql服务器会为其开辟一片连续的buffer pool,先写入buffer pool再找合适时机将缓存的数据写入磁盘。

image-20220301154525389

我们可以通过启动参数 innodb_log_buffer_size 来指定 log buffer 的大小,在 MySQL 5.7.21 这个版本中,该启动参数的默认值为 16MB 。

# redo log block

buffer pool 是由多个 redo log block组成

image-20220301154156508

# redo log block组成部分

  • log block body:真正的 redo 日志都是存储到占用 496 字节大小的 log block body 中,

  • log block header:存储的是一些管理信息。

  • log block trailer :LOG_BLOCK_CHECKSUM属性的意思如下:表示block的校验值,用于正确性校验,我们暂时不关心它。

# redo日志写入log buffer

InnoDB 的大叔特意提供了一个称之为 buf_free 的全局变量,该变量指明后续写入的 redo 日志应该写入到 log buffer 中的哪个位置

image-20220301155957554

我们前边说过一个 mtr 执行过程中可能产生若干条 redo 日志,这些 redo 日志是一个不可分割的组,所以其实并不是每生成一条 redo 日志,就将其插入到 log buffer 中,而是每个 mtr 运行过程中产生的日志先暂时存到一个地方,当该 mtr 结束的时候,将过程中产生的一组 redo 日志再全部复制到 log buffer 中。我们现在假设有两个名为 T1 、 T2 的事务,每个事务都包含2个 mtr ,我们给这几个 mtr 命名一下:

  • 事务 T1 的两个 mtr 分别称为 mtr_T1_1 和 mtr_T1_2 。
  • 事务 T2 的两个 mtr 分别称为 mtr_T2_1 和 mtr_T2_2 。

image-20220301160112031

不同的事务可能是并发执行的,所以 T1 、 T2 之间的 mtr 可能是交替执行的。每当一个 mtr 执行完成时,伴随该 mtr 生成的一组 redo 日志就需要被复制到 log buffer 中,也就是说不同事务的 mtr 可能是交替写入 log buffer 的,我们画个示意图(为了美观,我们把一个 mtr 中产生的所有的 redo 日志当作一个整体来画):

image-20220301160325344

从示意图中我们可以看出来,不同的 mtr 产生的一组 redo 日志占用的存储空间可能不一样,有的 mtr 产生的redo 日志量很少,比如 mtr_t1_1 、 mtr_t2_1 就被放到同一个block中存储,有的 mtr 产生的 redo 日志量非常大,比如 mtr_t1_2 产生的 redo 日志甚至占用了3个block来存储。

上次更新: 2025/06/04, 15:06:15
mysql之事务
redo日志(下)

← mysql之事务 redo日志(下)→

最近更新
01
AIIDE
03-07
02
githubActionCICD实战
03-07
03
windows安装Deep-Live-Cam教程
08-11
更多文章>
Theme by Vdoing
总访问量 次 | 总访客数 人
| Copyright © 2021-2025 ggball | 赣ICP备2021008769号-1
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式
×

评论

  • 评论 ssss
  • 回复
  • 评论 ssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssss
  • 回复
  • 评论 ssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssss
  • 回复
×