首页 > 数据库 >MySQL原理简介—7.redo日志的底层原理

MySQL原理简介—7.redo日志的底层原理

时间:2024-11-25 23:22:21浏览次数:5  
标签:Log Redo 磁盘 MySQL 原理 日志 redo log

大纲

1.redo日志对事务提交后数据不丢失的意义

2.redo日志文件的构成

3.redo日志会写入到Redo Log Blcok中

4.redo日志如何写入到Redo Log Blcok中

5.Redo Log Buffer解析

6.Redo Log Buffer的刷盘时机

7.undo log回滚日志原理

 

1.redo日志对事务提交后数据不丢失的意义

(1)redo log保证事务提交后修改的数据不丢失

(2)redo log出现的步骤分析

(3)修改过的缓存页刷盘和redo log刷盘的差别

 

(1)redo log保证事务提交后修改的数据不丢失

更新完缓存页后,必须要写一条redo log,这样才能记录对数据库的修改。

 

redo log可以保证事务提交后:如果事务中由增删改SQL更新的缓存页还没刷新到磁盘时MySQL宕机,那么MySQL重启后,就可以把redo log重做一遍,恢复事务在当时更新的缓存页,然后再把缓存页刷新到磁盘。

 

所以redo log的本质是保证事务提交后,修改的数据绝对不会丢失。

 

(2)redo log出现的步骤分析

步骤一:

MySQL在执行增删改SQL语句时,都是针对一个表中的某些数据执行的。此时首先会找到这个表对应的表空间,然后找到表空间对应的磁盘文件。接着从磁盘文件里把需要更新的数据所在的数据页从磁盘读取出来,也就是将磁盘上的数据页放到Buffer Pool中的缓存页里。

步骤二:

读取磁盘文件的数据页到Buffer Pool的缓存页后,MySQL就会根据增删改SQL语句对缓存页执行更新操作。

步骤三:

在MySQL更新缓存页时,会更新free链表、会更新flush链表、会更新LRU链表。然后后台有专门的IO线程,不定时根据flush链表、LRU链表,把更新过的缓存页(脏页)刷新回磁盘文件的数据页里。

 

但这种机制有个漏洞:万一事务里有增删改SQL语句更新了缓存页,事务提交了但还没来得及让IO线程把缓存页刷新到磁盘而MySQL宕机。这时Buffer Pool内存里的数据就会丢失,刚做完的事务更新数据也丢失。但也不可能每次提交一个事务,就把事务更新的缓存页刷新回磁盘文件。因为将缓存页刷新到磁盘文件里,是对磁盘随机写的,性能很差。这会导致数据库的性能和并发能力都很弱。

 

因此才引入了这个redo log机制。

步骤四:

提交事务时把MySQL对缓存页的修改以日志形式写入redo log日志文件。这种redo log日志的格式大致为:对表空间XX中的数据页XX中的偏移量为XXXX的地方更新了数据XXX。

只要事务提交时将所做修改以日志形式写入redo log,则宕机也没关系。因为重启后可以根据redo log,在Buffer Pool里恢复宕机前的事务更新。

 

(3)修改过的缓存页刷盘和redo log刷盘的差别

事务提交时把修改过的缓存页刷入磁盘,和事务提交时把所做修改的redo log写入日志文件的差别:

 

一.如果把修改过的缓存页都刷入磁盘

由于一个缓存页是16K,数据还是比较大的,将其刷入磁盘会比较耗时,且修改的缓存页可能仅有几字节的改动,把完整缓存页刷入磁盘不划算。

 

二.将缓存页刷入磁盘时是对磁盘进行随机写

这时由于一个缓存页对应的位置可能在磁盘文件的一个随机位置,比如偏移量为45336的地方,所以只能进行性能很差的磁盘随机写。

 

三.如果是将redo log写入日志文件

由于一行redo log只占几十字节,所以写入磁盘日志文件的速度会很快。其中redo log只包含表空间号、数据页号、磁盘文件偏移量、更新值。此外将redo log写入日志时是对磁盘进行顺序写,速度也很快。其中每次进行顺序写时都是直接追加到磁盘文件尾部的。所以提交事务时,使用数据量少 + 顺序写的redo log记录所做的修改,性能会远超直接刷新缓存页到磁盘,这可以让数据库的并发能力更强。

 

2.redo日志文件的构成

redo log日志本质上记录的是:对某个表空间的某个数据页的某个偏移量的地方修改了几个字节的值。

 

所以redo日志需要记录的就是:表空间号 + 数据页号 + 偏移量 + 修改几个字节的值 + 具体的值。

 

根据修改了数据页里多少个字节的值,redo日志类型就可以分为几种:MLOG_1BYTE类型的日志指的是修改了1个字节的值;MLOG_2BYTE类型的日志指的是修改了2个字节的值;以此类推,有修改了4个字节的值的日志类型,还有修改了8个字节的值的日志类型。当然,如果修改了一大串的值,就是MLOG_WRITE_STRING类型。

 

因此,一条redo日志的结构大致如下:

日志类型(类似MLOG_1BYTE之类的),表空间ID,数据页号,数据页中的偏移量,具体修改的数据

通过这样的日志,MySQL可以知道:这次增删改操作修改了多少字节的数据,在哪个表空间操作的,在哪个数据页执行的,在哪个偏移量开始的,具体的更新数据又是多少。由此就可以精准完美地还原出一次数据增删改操作做的变动了。

 

如果是MLOG_WRITE_STRING类型的日志,因为不知道修改了多少字节的数据,所以会多一个修改数据长度,格式如下:

日志类型(类似MLOG_1BYTE之类的),表空间ID,数据页号,数据页中的偏移量,修改数据长度,具体修改的数据

 

3.redo日志会写入到Redo Log Blcok中

每条redo日志记录的是:表空间号 + 数据页号 + 偏移量 + 修改几个字节的值 + 具体的值。

 

实际写入磁盘时,Redo Log并不是按上述格式写入到日志文件里的。MySQL内有一个数据结构,叫做Redo Log Blcok。redo日志是用一个Redo Log Blcok来存放多个单行日志的。

 

一个Redo Log Block是512字节,分为3个部分:一是12字节的Header,二是496字节的Body,三是4字节的Trailer。

 

其中,12字节的Header头又分为4个部分:

一.4个字节的Block No,就是块唯一编号;

二.2个字节的Data Length,就是Block里写入了多少字节数据;

三.2个字节的First Record Group,每个事务都会有多个Redo Log,对应于一组Redo Log。在该Block里的第一组Redo Log的偏移量,就是这2个字节;

四.4个字节的Checkpoint NO;

从上图可知:每个redo日志都是写入到文件里的一个Redo Log Block里去的,一个Redo Log Block最多放496字节Redo Log日志。

 

4.redo日志如何写入到Redo Log Blcok中

往一个文件里写数据,可认为是从第一行开始从左往右写,会有很多行。

 

假设现在要写第一条redo日志:首先会把该日志数据放到内存中的一个叫Redo Log Block的数据结构里,然后不断往这个Redo Log Block的数据结构添加一条条redo日志,直到内存里的这个Redo Log Block满了,已经达到512字节。当一个Redo Log Block满时,再一次性把它写入到磁盘文件。

 

下图展示了redo log和Redo Log Block的关系:

写文件时可以按照字节,一个字节一个字节地写入。文件里存放的东西就是很多很多字节,依次排开。其中可能512个字节会组合起来,就固定代表一个Redo Log Block。这也是中间件系统、数据库系统,底层依赖磁盘文件存储数据的原理。

 

在磁盘文件的末尾不停写入字节数据,就是磁盘顺序写。在磁盘文件的某个位置找到一个Redo Log Block去修改几个字节的数据,就是磁盘随机写。

 

5.Redo Log Buffer解析

已知MySQL执行完增删改的SQL语句后:会先让redo日志进入Redo Log Block,然后再写入磁盘的redo日志文件。

 

Redo Log Buffer是MySQL启动时向操作系统申请的一块连续内存空间。Buffer Pool也是MySQL启动时向操作系统申请的一块连续内存空间。Buffer Pool会在申请内存后划分很多空的缓存页和一些链表结构。Redo Log Buffer也会在申请内存后,划分很多空的Redo Log Block。

innodb_log_buffer_size可配置Redo Log Buffer的大小,默认是16MB。其实16MB已经够大了,毕竟一个Redo Log Block才512字节,每条redo日志也就几个到几十个字节而已。

 

从Redo Log Buffer结构可知:当要写一条redo日志时,就会从第一个Redo Log Block开始写入。写满了一个Redo Log Block,就会继续写下一个Redo Log Block。以此类推,直到所有Redo Log Block写满。当Redo Log Buffer里的所有Redo Log Block都被写满后,此时就会强制把Redo Log Block刷入到磁盘中。

 

当一个Redo Log Block满512字节后,也会被追加到redo日志文件里。然后在磁盘文件里不停地追加一个又一个的Redo Log Block。

此外,MySQL平时执行一个事务的过程中,每个事务都会有多个增删改操作,这样就会有多条redo日志。这多条redo日志就是一组Redo Log Group,每次一组Redo Log Group都先在别的地方暂存,执行完后再把一组redo日志写到Redo Log Block里。

 

如果一组Redo Log Group中的redo日志太多,那么就可能会将其存放在两个Redo Log Block中。如果一组Redo Log Group比较小,那么也可能多个Redo Log Group是在一个Redo Log Block里。

 

6.Redo Log Buffer的刷盘时机

(1)Redo Log Block什么时候刷盘

(2)redo log日志刷盘的场景

(3)磁盘上到底有几个redo日志文件

 

(1)Redo Log Block什么时候刷盘

时机一:Redo Log Buffer已使用过半时

如果Redo Log Buffer的日志已占据Redo Log Buffer总容量16M的一半,即超过了8MB的redo日志在缓冲里,此时就会把它们刷入磁盘文件中。

 

时机二:事务被提交时

一个事务提交时,要把其redo日志所在的Redo Log Block刷入磁盘文件。这样它修改的数据才不会丢失,随时可通过redo日志恢复事务所做修改。

(innodb_flush_log_at_trx_commit的值为1)

 

时机三:后台线程定时刷新

有个后台线程会每秒把Redo Log Buffer的Redo Log Block刷到磁盘文件。

 

时机四:关闭MySQL时

当关闭MySQL时,Redo Log Buffer的Redo Log Block都会刷入到磁盘里。

 

(2)redo log日志刷盘的场景

场景一:

MySQL瞬间执行了大量高并发SQL,1秒就产生了超过8MB的redo日志。此时这些redo日志占据了Redo Log Buffer的一半空间,于是就会刷盘。

 

这种redo日志刷盘,在MySQL承受高并发请求时是比较常见的。比如每秒执行上万个增删改SQL,每个SQL的redo日志有几百个字节。此时是可能1s生成超8MB的redo日志的,从而触发刷新redo日志到磁盘。但是这种高并发请求的情况一般不常见。

 

场景二:

正常情况执行一个事务,一般会在几十毫秒到几百毫秒间执行完毕。通常MySQL单事务性能一般不会超过1秒,否则就太慢了。所以执行完一个事务,也会马上把这个事务的redo日志刷入磁盘。这种情况则比较常见,当一个短事务提交时往往会发生redo日志刷盘。

 

场景三:

后台线程每秒自动刷新redo日志到磁盘去。

 

总而言之:

一个事务执行时,事务对应的redo日志都进入到Redo Log Buffer。一个事务提交时,事务对应的redo日志刷入磁盘文件才算事务提交成功。这样才能确保事务提交后,数据不会丢,只要有redo日志在磁盘里就行。

 

(3)磁盘上到底有几个redo日志文件

大量的redo日志是否都放在一个文件里,磁盘空间是否会越占越多?默认情况下,redo log都会写入一个目录中的文件里。这个目录可通过show variables like 'datadir'来查看,可通过innodb_log_group_home_dir参数来进行设置。

 

redo日志文件是有多个的,写满了一个就会写下一个redo日志文件。可以限制redo日志文件的数量。通过innodb_log_file_size可指定每个redo日文件的大小,默认48MB;通过innodb_log_files_in_group可指定redo日志文件的数量,默认2个。

 

所以,默认情况下,目录里就两个日志文件,分别为ib_logfile0和ib_logfile1,每个48MB。先写满第一个再进行写满第二个,一个写满了交替覆盖式去写另外一个。

 

因此,MySQL最多只保留最近的96MB的redo日志而已。事实上这已足够多了,毕竟一条redo log通常就几个字节到几十个字节,96MB已足够存储上百万条redo log了。

 

7.undo log回滚日志原理

(1)redo log应对的场景—事务提交数据丢失

(2)undo log应对的场景—进行事务回滚

(3)undo log回滚日志的作用

(4)undo log日志长什么样

 

(1)redo log应对的场景—事务提交数据丢失

已知对Buffer Pool里的缓存页执行增删改操作时,必须要写对应的redo log日志记录下要做的哪些修改。redo log日志都会先进入Redo Log Buffer中的一个Redo Log Blcok,然后事务提交时会将Redo Log Block刷入到磁盘的redo日志文件里。

 

万一事务已提交,而事务修改的缓存页还没刷入磁盘上的数据页文件。此时MySQL宕机,那么Buffer Pool里被事务修改过的数据就全部丢失。

 

但只要有redo log,MySQL重启后又可以把那些还没刷入磁盘的缓存页它们所对应的redo log都加载出来,在Buffer Pool的缓存页里重做一遍,这样就可以保证事务提交之后,修改的数据绝对不会丢。

 

(2)undo log应对的场景—进行事务回滚

假设现在在一个事务里要执行一些增删改操作:那么需要先把对应的数据页从磁盘加载出来放到Buffer Pool的缓存页,然后在缓存页进行增删改,同时记录redo log。

 

但万一这个事务里的增删改操作执行了一半时,需要进行事务回滚。比如一个事务里有4个增删改操作,结果已经执行了2个增删改SQL。已经更新了一些Buffer Pool的数据,但还有2个增删改SQL还没执行。此时需要回滚事务该怎么处理?

此时如果要回滚事务,就必须对已经在Buffer Pool缓存页里执行过的增删改SQL操作进行回滚。所以才必须引入另外一种日志,就是undo log回滚日志。

 

这个回滚日志,记录的东西非常简单;

一.比如在缓存页里执行了一条insert语句

那么记录该操作的回滚日志就必须有一个主键和一个对应的delete操作;

二.比如在缓存页里执行了一条delete语句

那么需要记录删除的语句,回滚时就可以执行一条insert操作恢复数据;

三.比如在缓存页里执行了一条update语句

那么需要记录更新前的值,回滚时就可以把更新前的值更新回去;

四.如果执行的是select语句

那么由于select语句并没有在Buffer Pool里执行修改,故无需undo log;

(3)undo log回滚日志的作用

执行事务时,很多insert、update和delete语句都在更新缓存页的数据。如果事务回滚,需要根据每条SQL对应的undo log回滚日志恢复数据。

 

比如执行了INSERT语句:

则undo log必须记录插入数据的主键ID,回滚时从缓存页里把数据删除;

比如执行了DELETE语句:

则undo log必须记录被删除的数据,回滚时才可以重新插入一条数据;

如果执行了UPDATE语句:

则undo log必须记录修改之前的数据,回滚时才可以把数据更新回去;

 

(4)undo log日志长什么样

undo log日志里的内容为:这条日志的开始位置、主键的各列长度和值、表ID、undo log日志编号、undo log日志类型、这条日志的结束位置。

其中主键的各列长度和值,指这条数据的主键的每个列的长度和值是多少。如果表没有设置主键,MySQL会设置一个隐藏字段row_id作为表的主键。undo log日志类型,比如INSERT语句的就是TRX_UNDO_INSERT_REC。

 

标签:Log,Redo,磁盘,MySQL,原理,日志,redo,log
From: https://www.cnblogs.com/mjunz/p/18569023

相关文章

  • MySQL原理简介—8.MySQL并发事务处理
    大纲1.简单总结增删改SQL语句的实现原理2.多个事务同时执行的场景遇到的问题3.多个事务并发更新或查询时可能出现的问题4.SQL标准中对事务的4个隔离级别5.MySQL是如何支持4种事务隔离级别的6.Spring事务注解了如何设置隔离级别7.uodolog多版本链介绍8.基于undolog多版本......
  • ConcurrentHashMap原理
        相信大家在面试的时候经常被问到类似问题:“实现HashMap线程安全的办法有哪些”“jdk1.7和jdk1.8在HashMap上面有什么区别?”“ConcurrentHashMap底层是怎么保证线程安全的”……当面试官问到HashMap的线程安全问题的时候大概率是想让你往ConcurretHashMap方向回答了......
  • 基于Java+SpringBoot+Mysql在线简单拍卖竞价拍卖竞拍系统功能设计与实现七
    一、前言介绍:免费学习:猿来入此1.1项目摘要主要源于互联网技术的快速发展和电子商务的普及。随着网络技术的不断进步,人们越来越依赖于互联网进行购物、交易和沟通。电子商务的兴起为在线拍卖提供了广阔的市场和便利的条件。在线拍卖系统通过搭建一个虚拟的拍卖平台,将传统......
  • 基于Java+SpringBoot+Mysql在线简单拍卖竞价拍卖竞拍系统功能设计与实现八
    一、前言介绍:免费学习:猿来入此1.1项目摘要主要源于互联网技术的快速发展和电子商务的普及。随着网络技术的不断进步,人们越来越依赖于互联网进行购物、交易和沟通。电子商务的兴起为在线拍卖提供了广阔的市场和便利的条件。在线拍卖系统通过搭建一个虚拟的拍卖平台,将传统......
  • RMI原理及常见反序列化攻击手法
    这是对网上一些文章和视频的再总结,可以参考以下资料,师傅们分析的都挺详细了,我这就是记录一下师傅们写的博客。廖雪峰-给了简单的小例子,了解即可B站视频(白师傅)先知社区(小阳师傅)-讲的比较详细,偏理论,可以结合白师傅的视频学习理论g师傅-攻击手法讲的特别详细,学完理论后......
  • JavaWeb——SpringBoot原理
    10.1.配置优先级10.1.1.配置文件properties>yml(推荐)>yaml10.1.2.Java系统属性、命令行参数命令行参数>Java系统属性>配置文件10.2.Bean管理10.2.1.手动获取beanApplicationContext,IOC容器对象10.2.2.bean作用域10.2.3.第三方bean自定义的......
  • 【Z2400012】基于Java+SpringBoot+Vue+mysql实现的职工管理系统(附源码 配置 文档)
    职工管理系统1.摘要2.开发目的和意义3.系统功能设计4.系统界面截图5.源码获取1.摘要本系统是一个基于SpringBoot和Vue框架实现的职工管理系统,旨在满足现代公司和组织对员工信息、考勤、工资等多方面的管理需求。系统设计了管理员、人事经理、职工三种角色,每种角色拥......
  • vue等框架的响应式原理(简化)
    初次发布于我的个人文档本文简要介绍一下如何实现一个简化版的类vue的响应式。1.假装不知道响应式如果我们不知道vue等响应式框架,那么又该如何手动实现类似的功能呢?先来看这么一个简单的页面<!DOCTYPEhtml><htmllang="zh-CN"><head><title>MyProgram</title><......
  • 多平台数据集成的实践案例:吉客云到MySQL
    测试-查询销售渠道信息(已删除数据)-dange:吉客云数据集成到MySQL的技术案例分享在现代企业的数据管理中,如何高效、可靠地实现多平台间的数据集成是一个关键问题。本次我们将聚焦于一个具体的系统对接案例,即将吉客云中的销售渠道信息(包括已删除数据)集成到MySQL数据库中。该方案名......
  • 【MySQL】数据库的隔离级
    数据库的隔离级别是指多个事务并发执行时,数据库系统应该如何保证事务之间的隔离程度。不同的隔离级别具有不同的并发控制策略,从而影响了事务的隔离性、性能和并发度。一、隔离级别的分类根据ANSI/ISOSQL标准,数据库隔离级别分为以下四种:读未提交(ReadUncommitted)最低级......