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

Mysql redolog

一、redolog 是啥

数据库的ACID:A原子性,C一致性,I隔离性,D持久性;

redolog:保证 持久性;

redolog: 系统奔溃重启时需要按照上述内容所记录的步骤重新更新数据页,特点:

1、redo 日志占用空间非常小:存储表空间ID、页号、偏移量以及需要更新的值所需的存储空间。

2、redo 日志顺序写入磁盘:执行事务时,产生若干条 redo 日志,按顺序写入磁盘,顺序IO。

二、redlog日志格式

type:该条 redo 日志的类型。
space ID:表空间ID。 
page number:页号。 
data:该条 redo 日志的具体内容。

三、乐观插入与悲观插入

悲观插入:产生页分裂,一条数据插入会产生多条redlog,最后一条必须以一个特殊的redolog结尾MLOG_MULTI_REC_END,type 字 段对应的十进制数字为 31。

 四、Mini-Transaction的概念

把对底层页面中的一次原子访问的过程称之为一个 Mini-Transaction ,简称 mtr。比如:向某个索引对应的 B+ 树中插入一条记录的过程 也算是一个 Mini-Transaction 。一个所谓的 mtr 可以包含一组 redo 日志,在进 行奔溃恢复时这一组 redo 日志作为一个不可分割的整体。

五、redo日志的写入过程 

5.1 redo log block

通过 mtr 生成的 redo 日志都放在了大小为 512字节 的页中。为了和我们前边提到的表空间中的页做区别,我们这里把用来存储 redo 日志的页称为 block。

log block header 的几个属性的意思分别如下:
1、LOG_BLOCK_HDR_NO:每一个block都有一个大于0的唯一标号,本属性就表示该标号值。
2、LOG_BLOCK_HDR_DATA_LEN :表示block中已经使用了多少字节,初始值为 12 (因为 log block body 从第12个字节处开始)。随着往block中写入的redo日志越来也多,本属性值也跟着增长。如果 log block body已经被全部写满,那么本属性的值被设置为 512 。
3、LOG_BLOCK_FIRST_REC_GROUP :一条 redo 日志也可以称之为一条 redo 日志记录( redo log record ),一个 mtr 会生产多条 redo 日志记录,这些 redo 日志记录被称之为一个 redo 日志记录组( redo logrecord group )。 LOG_BLOCK_FIRST_REC_GROUP 就代表该block中第一个 mtr 生成的 redo 日志记录组的偏移量(其实也就是这个block里第一个 mtr 生成的第一条 redo 日志的偏移量)。
4、LOG_BLOCK_CHECKPOINT_NO :表示所谓的 checkpoint 的序号.
log block trailer 中属性的意思如下:
LOG_BLOCK_CHECKSUM :表示block的校验值,用于正确性校验,我们暂时不关心它。

5.2 redo log buffer

写入 redo 日 志时也不能直接直接写到磁盘上,实际上在服务器启动时就向操作系统申请了一大片称之为 redo log buffer 的 连续内存空间,参数innodb_log_buffer_size(默认16M)。结构如下:

 5.3 redo log 写入log buffer

log buffer 中写入 redo 日志的过程是顺序的,需要知道下一个往哪个block(页?)中写。

buf_free:该变量指明后 续写入的 redo 日志应该写入到 log buffer 中的哪个位置:

一个 mtr 执行过程中可能产生若干条 redo 日志,这些 redo 日志是一个不可分割的组,每个 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 。

每个 mtr 都会产生一组 redo 日志,用示意图来描述一下这些 mtr 产生的日志情况:

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

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

五 redolog File

5.1 redolog buffer 刷盘时机

1、log buffer 空间不足时:log buffer 的 redo 日志量已经占满了 log buffer 总容量的大约一半左右,就需要把这些日志刷新到磁盘上。(通过系统变量 innodb_log_buffer_size 指定)

2、事务提交时:保证持久性,必须要把修改这些页面对应的 redo 日志刷新到 磁盘。

3、后台线程不停的刷:大约每秒都会刷新一次 log buffer 中的 redo 日志到磁盘。

4、正常关闭服务器时和 checkpoint 时

5.2 redo日志文件组

log buffer默认刷新到ib_logfile0和ib_logfile1两个文件中,

innodb_log_group_home_dir:ib_logfile0和ib_logfile1文件目录。

innodb_log_file_size:两个文件大小,默认值为 48MB 。

innodb_log_files_in_group:redo 日志文件的个数,默认值为2,最大值为100。

写入日志组过程

在将 redo 日志写入 日志文件组时,从 ib_logfile0 开始写,如果 ib_logfile0 写满了,就接着 ib_logfile1 写,ib_logfile1 写满了就去 写 ib_logfile2 ,依此类推。如果写到最后一个文件该咋办?那就重新转到 ib_logfile0 继续写;

5.3 redo log文件格式
****log buffer中的redo日志刷新到磁盘的本质,就是把block的镜像写入日志文件中 ****,redo 日志文件其实也是由若干 个 512 字节大小的block组成:
        前2048个字节,也就是前4个block是用来存储一些管理信息的。 
        从第2048字节往后是用来存储 log buffer 中的block镜像的。

 5.3 Log Sequeue Number(LSN)

lsn: 记录已经写入的 redo 日志量(日志序列号),初始的 lsn 值为 8704;数据写入示例如下:

5.3.1 初始启动时(8704+增长值)

系统第一次启动后初始化 log buffer 时, buf_free (就是标记下一条 redo 日志应该写入到 log buffer 的位置的变量)就会指向第一个 block 的偏移量为12字节( log block header 的大小)的地方,那么 lsn 值也会跟着增加12:

5.3.2 剩余空间够用时(直接加法操作)

如果某个 mtr 产生的一组 redo 日志占用的存储空间比较小,待插入的block剩余空闲空间能容纳这 个 mtr 提交的日志时, lsn 增长的量就是该 mtr 生成的 redo 日志占用的字节数,就像这样:

假设上图中 mtr_1 产生的 redo 日志量为200字节,lsn 就要在 8716 的基础上增加 200 ,为 8916

5.3.3 剩余空间不足时(额外加上 log block header,log block trailer)

如果某个 mtr 产生的一组 redo 日志占用的存储空间比较大,也就是待插入的block剩余空闲空间不足以容纳 这个 mtr 提交的日志时, lsn 增长的量就是该 mtr 生成的 redo 日志占用的字节数加上额外占用的 log block header 和 log block trailer 的字节数,就像这样:

我们假设上图中 mtr_2 产生的 redo 日志量为1000字节,为了将 mtr_2 产生的 redo 日志写入 log buffer ,我们不得不额外多分配两个block,所以 lsn 的值需要在 8916 的基础上增加 1000 + 12×2 + 4 × 2 = 1032 

5.4 flushed_to_disk_lsn

buf_next_to_write:记录log buffer中哪些被刷盘(刷盘之前先写到log buffer)。

5.5 lsn值和redo日志文件偏移量的对应关系

初始时的 LSN 值是 8704 ,对应文件偏移量 2048 ,之后每个 mtr 向磁盘中写入多少字节日志, lsn 的值就增长 多少。

 5.6 flush链表中的LSN和mtr作用

5.6.1 mtr作用

1、可能会产生一组不可分割的 redo 日志,在mtr结束时,会把这一组 redo 日志写入到 log buffer 
2、把在mtr执行过程中可能修改过的页面加入到Buffer Pool的flush链表

5.6.2 flush更新lsn过程

oldest_modification :如果某个页面被加载到 Buffer Pool 后进行第一次修改,那么就将修改该页面的 mtr 开始时对应的 lsn 值写入这个属性。

newest_modification :每修改一次页面,都会将修改该页面的 mtr 结束时对应的 lsn 值写入这个属性。 也就是说该属性表示页面最近一次修改后对应的系统 lsn 值。 

页面写入过程示意图:

flush链表中的脏页按修改发生的时间顺序进行排序,按照 oldest_modification代表的LSN值进行排序,被多次更新的页面不会重复插入到flush链表中,但会更新 newest_modification属性值。 

5.7 checkpoint 和checkpoint_lsn

5.7.1 存在的意义

判断某些redo log占用的磁盘空间是否可以覆盖的依据就是它对应的脏页是否已经刷新到磁盘里。

flush链表,log buffer,log file 日志写入示意图:

如图,虽然 mtr_1 和 mtr_2 生成的 redo 日志都已经被写到了磁盘上,但是它们修改的脏页仍然留在 Buffer Pool 中,所以它们生成的 redo 日志在磁盘上的空间是不可以被覆盖的。之后随着系统的运行,如果 页a 被刷新 到了磁盘,那么它对应的控制块就会从 flush链表 中移除,就像这样子: 

 5.7.2 checkpoint_lsn

 代表当前系统中可以被覆盖的 redo 日志总量是多少,这个变量初始值也是 8704。页a 被刷新到磁盘, mtr_1 生成的 redo 日志就可以被覆盖,所以我们可以进行一个增加 checkpoint_lsn 的操作,我们把这个过程称之为做一次 checkpoint。步骤如下:

1、计算一下当前系统中可以被覆盖的 redo 日志对应的 lsn 值最大是多少。

redo 日志可以被覆盖,意味着它对应的脏页被刷到了磁盘,只要我们计算出当前系统中被最早修改的脏页 对应的 oldest_modification 值,那凡是在系统lsn值小于该节点的oldest_modification值时产生的redo日志 都是可以被覆盖掉的,我们就把该脏页的 oldest_modification 赋值给 checkpoint_lsn 。 比方说当前系统中 页a 已经被刷新到磁盘,那么 flush链表 的尾节点就是 页c ,该节点就是当前系统中最 早修改的脏页了,它的 oldest_modification 值为8916,我们就把8916赋值给 checkpoint_lsn (也就是说 在redo日志对应的lsn值小于8916时就可以被覆盖掉)。

2、checkpoint_lsn 和对应的 redo 日志文件组偏移量以及此次 checkpint 的编号写到日志文件的 管理信息(就是 checkpoint1 或者 checkpoint2 )中。

5.8 innodb_flush_log_at_trx_commit的用法 

0: 事务提交时,每次都会写入logbuffer ,但是只会定时(每秒)写入(调用fsync)osbuffer ,在写入到磁盘文件,可能会丢失1 秒内的数据。
1: mysql默认规则,事务提交时每次都写入 logbuffer、osbuffer、刷新到磁盘。数据完整性能低。
2: 事务提交时每次都写入osbuffer,但是每秒执行一次写入磁盘操作。

5.9 奔溃恢复

5.9.1 奔溃恢复起点

对于 checkpoint_lsn 之后的 redo 日志,它 们对应的脏页可能没被刷盘,也可能被刷盘了,我们不能确定,所以需要从 checkpoint_lsn 开始读取 redo 日志 来恢复页面。要把 checkpoint1 checkpoint2 这两个block中的 checkpoint_no 值读出来比一下大小,哪个的 checkpoint_no 值更大,说明哪个block存储的就是最近的一次 checkpoint 信息。这样我们就能拿到最近发生 的 checkpoint 对应的 checkpoint_lsn 值以及它在 redo 日志文件组中的偏移量 checkpoint_offset

5.9.2 确定恢复的终点

根据block扫描到最后一个block(没写满的block)

5.9.3 怎么恢复

根据 redo 日志的 space ID 和 page number 属性计算出散列值,把 space ID 和 page number 相同的 redo 日志放到哈希表的同一个槽里,如果有多个 space ID 和 page number 都相同的 redo 日志,那么它们之间 使用链表连接起来,按照生成的先后顺序链接起来的

同一个页面进行修改的 redo 日志都放在了一个槽里,所以可以一次性将一 个页面修复好(避免了很多读取页面的随机IO),这样可以加快恢复速度。另外需要注意一点的是,同一个 页面的 redo 日志是按照生成时间顺序进行排序的,所以恢复的时候也是按照这个顺序进行恢复,如果不按 照生成时间顺序进行排序的话,那么可能出现错误。比如原先的修改操作是先插入一条记录,再删除该条记 录,如果恢复时不按照这个顺序来,就可能变成先删除一条记录,再插入一条记录,这显然是错误的。

相关文章:

Mysql redolog

一、redolog 是啥 数据库的ACID:A原子性,C一致性,I隔离性,D持久性; redolog:保证 持久性; redolog: 系统奔溃重启时需要按照上述内容所记录的步骤重新更新数据页,特点&#xff1a…...

【设计模式】Head First 设计模式——桥模式 C++实现

设计模式最大的作用就是在变化和稳定中间寻找隔离点,然后分离它们,从而管理变化。将变化像小兔子一样关到笼子里,让它在笼子里随便跳,而不至于跳出来把你整个房间给污染掉。 设计思想 桥模式。将抽象部分(业务功能)与实现部分(平…...

CESM2代码下载

这半年忙着毕业写论文,好久好久好久不更新了∠( ω)/ ,今天准备开个新坑 ๑乛◡乛๑,学习一下CESM(Community Earth System Model),它是一个完全耦合的全球气候模型,可用于地球过去、…...

编写OpenCL程序的基本步骤

opencl pyopencl OpenCL-Headers OpenCL(全称为Open Computing Langugae,开放运算语言)是第一个面向异构系统(此系统中可由CPU,GPU或其它类型的处理器架构组成)的并行编程的开放式标准。 它是跨平台的。 OpenCL由两部分组成,一是用于编写…...

计算机网络之TCP/IP协议第一篇:网络基础知识

文章目录 写给自己的话 一:前言 1:手握金刚钻的TCP/IP 2:计算机中的协议 3:分组...

虚拟机扩容

系统环境centos8,分两步,第一步先在vmware扩容,第二部在虚拟机内部扩容 1.vmware分配磁盘空间 2.虚拟机内部扩容 查看当前磁盘信息,这个是扩容之前的,扩容完成才会显示新的 df -h查看系统分区信息 fdisk -l查看目录…...

Linux下的系统编程——进程间的通信(九)

一、进程间通信常用方式 IPC方式: Linux环境下,进程地址空间相互独立,每个进程各自有不同的用户地址空间。任何一个进程的全局变量在另一个进程中都看不到,所以进程和进程之间不能相互访问,要交换数据必须通过内核&am…...

Qt QtableWidget、QtableView表格删除选中行、删除单行、删除多行

文章目录 Qt QtableWidget表格删除选中行只能选择一行,点击按钮后,删除一行可以选择中多行,点击按钮后,删除多行选中某一列中的不同行,点击按钮后,删除多行 QTableWidgetSelectionRange介绍QTableWidget的选…...

【代码随想录day24】不同的二叉搜索树

题目 给你一个整数 n ,求恰由 n 个节点组成且节点值从 1 到 n 互不相同的 二叉搜索树 有多少种?返回满足题意的二叉搜索树的种数。 示例 1: 输入:n 3 输出:5示例 2: 输入:n 1 输出&#xf…...

数学建模--Subplot绘图的Python实现

目录 1.Subplot函数简介 2.Subplot绘图范例1:绘制规则子图 3.Subplot绘图范例2:绘制不规则子图 4.Subplot绘图范例3:gridspec辅助实战1 5.Subplot绘图范例4:gridspec辅助实战2 1.Subplot函数简介 """ 最近在数学建模种需要绘制多张子图,发现对于subplot函…...

JMeter(三十九):selenium怪异的UI自动化测试组合

文章目录 一、背景二、JMeter+selenium使用过程三、总结一、背景 题主多年前在某社区看到有人使用jmeter+selenium做UI自动化测试的时候,感觉很是诧异、怪异,为啥?众所周知在python/java+selenium+testng/pytest这样的组合框架下,为啥要选择jmeter这个东西[本身定位是接口测…...

c++ 移动构造方法为什么要加noexcept

背景: 最近看了候捷老师的c的教程, 他说移动构造方法要加noexcept, 在vector扩容的时候, 如果有移动构造方法没有加noexcept,是不会调用的. 个人感觉有些神奇, 这就去查下一探究竟. 过程: 测试代码如下: #include <iostream> #include <vector> struct A {A(){s…...

鸿鹄工程项目管理系统 Spring Cloud+Spring Boot+前后端分离构建工程项目管理系统

工程项目管理软件&#xff08;工程项目管理系统&#xff09;对建设工程项目管理组织建设、项目策划决策、规划设计、施工建设到竣工交付、总结评估、运维运营&#xff0c;全过程、全方位的对项目进行综合管理 工程项目各模块及其功能点清单 一、系统管理 1、数据字典&am…...

手把手教你搭建园林园艺小程序商城

现如今&#xff0c;随着互联网的快速发展&#xff0c;小程序成为了企业和个人展示产品和服务的新方式。在园林园艺行业&#xff0c;构建一个园林园艺小程序能够更好地推广和销售自己的产品和服务。那么&#xff0c;如何构建一个园林园艺小程序呢&#xff1f;下面我们来详细介绍…...

Java Iterator(迭代器)

Java迭代器&#xff08;Iterator&#xff09;是 Java 集合框架中的一种机制&#xff0c;是一种用于遍历集合&#xff08;如列表、集合和映射等&#xff09;的接口。 它提供了一种统一的方式来访问集合中的元素&#xff0c;而不需要了解底层集合的具体实现细节。 Iterator 是 …...

Logstash同步MySQL数据到ElasticSearch

当MySQL数据到一定的数量级&#xff0c;而且索引不能实现时&#xff0c;查询就会变得非常缓慢&#xff0c;所以使用ElasticSearch来查询数据。本篇博客介绍使用Logstash同步MySQL数据到ElasticSearch&#xff0c;再进行查询。 测试环境 Windows系统MySQL 5.7Logstash 7.0.1El…...

【C++】运算符重载的示例实现和应用

C运算符重载的格式&#xff1a; operator 运算符 比如要重载 ! 运算符 &#xff1a; operator ! 下面是一个例子&#xff1a; class DemoText{DemoText(string str, int num){m_text str; m_number num;}string m_text;int m_number; }这里来定义两个对象&#xff1a;…...

Kubernetes禁止调度

在Kubernetes中&#xff0c;您可以通过几种方式来禁止某个Pod调度到节点上。以下是一些方法&#xff1a; Node Selector&#xff1a;您可以使用Node Selector来限制Pod只能调度到带有特定标签的节点上。如果您希望完全禁止Pod调度到某些节点上&#xff0c;可以确保这些节点不拥…...

CocosCreator3.8研究笔记(七)CocosCreator 节点和组件的介绍

相信很多新手朋友&#xff0c;肯定会问&#xff0c;CocosCreator 中什么是节点&#xff1f;什么是组件&#xff1f; 一、什么是组件&#xff08;Component&#xff09;&#xff1f; Cocos Creator 3.8 的工作流程是以组件式开发为核心&#xff0c;即以组合而非继承的方式进行游…...

Ceph入门到精通-C++入门知识点

C中的双冒号(::)是作用域分解运算符&#xff08;scope resolution operator&#xff09;。 它主要有以下两种用法&#xff1a; 用于区分同名的不同成员&#xff0c;例如在不同类中声明了同名的成员函数或成员变量&#xff0c;可以使用A::B的方式来特指A类的B成员。当全局变量…...

Ansible之playbook详解和应用实例

目录 一、playbook简介 1.什么是playbook 2.playbook组成 二、应用实例 1.使用playbook安装启用httpd服务 2.使用playbook安装启用nginx服务 三、ansible-playbook其他用法 1.检查yaml文件的语法是否正确 2.检查tasks任务 3.检查指定的主机 4.指定从某个task开始运行…...

经验萃取方法

【经验萃取】 经验萃取不是简单的总结提炼归纳&#xff01; 经验萃取需经过还原、复盘分析、萃取重构 一.经验萃取前三个准备 1.定主题&#xff1a; 萃取主题选择&#xff08;阐述原因、确定级别、差距/问题是源头&#xff09;->多维评分&#xff1a;普遍性、重要性、迫切…...

手写apply方法

<script>/** 手写apply方法 * */Function.prototype.myApply function (context, args) {console.log(this, sss)//fnconst key Symbol()context[key] thiscontext[key](...args)delete context[key]return context[key]}const obj {name: zs,age: 18}function fn …...

Jenkins实现基础CD操作

操作截图 在Jenkins里面设置通过标签进行构建 在Jenkins中进入项目&#xff0c;配置以下 将execute shell换到invoke top-level maven targets之前 在gitlab中配置标签 代码迭代新的版本 项目代码迭代 修改docker-compose.yml 提交新版本的代码 在Jenkins中追加新…...

开源软件合集(Docker)

Docker安装 1.安装命令&#xff1a;curl -fsSL https://get.docker.com | bash -s docker --mirror Aliyun2.启动&#xff1a;systemctl start docker3.停止&#xff1a;systemctl stop docker4.重启&#xff1a;systemctl restart docker5.开机启动&#xff1a;systemctl enab…...

Ceph入门到精通-生产日志级别设置

Ceph 子系统及其日志记录级别的信息。 了解 Ceph 子系统及其日志记录级别 Ceph 由多个子系统组成&#xff1a; 每个子系统都有其日志记录级别&#xff1a; 默认情况下存储在 /var/log/ceph/ 目录中的输出日志&#xff08;日志级别&#xff09;存储在内存缓存中的日志&#…...

16-MyCat

一 Mycat概述 1 什么是Mycat 什么是Mycat Mycat是数据库中间件&#xff0c;所谓数据库中间件是连接Java应用程序和数据库中间的软件。 为什么要用Mycat 遇到问题&#xff1a; Java与数据库的紧耦合高访问量高并发对数据库的压力读写请求数据不一致 2 Mycat与其他中间件区别 目…...

RKNPU2通用API和零拷贝API

RKNPU2通用API 通用API接口按照异构编程规范&#xff0c;需要将数据拷贝到NPU运行时的内存空间。 通用API部署流程 初始化上下文&#xff0c;需要先创建上下文对象和读取模型文件 rknn_context ctx; model load_model(model_path, &model_len); ret rknn_init(&ctx…...

LeetCode 1123. 最深叶节点的最近公共祖先:DFS

【LetMeFly】1123.最深叶节点的最近公共祖先 力扣题目链接&#xff1a;https://leetcode.cn/problems/lowest-common-ancestor-of-deepest-leaves/ 给你一个有根节点 root 的二叉树&#xff0c;返回它 最深的叶节点的最近公共祖先 。 回想一下&#xff1a; 叶节点 是二叉树…...

多线程应用——线程池

线程池 文章目录 线程池1.什么是线程池2.为什么要用线程池3.怎么使用线程池4.工厂模式5.自己实现一个线程池6.创建系统自带的线程池6.1 拒绝策略6.2 线程池的工作流程 1.什么是线程池 字面意思&#xff0c;一次创建多个线程&#xff0c;放在一个池子(集合类)&#xff0c;用的时…...