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

本文涉及的产品
RDS PostgreSQL Serverless,0.5-4RCU 50GB 3个月
推荐场景:
对影评进行热评分析
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS SQL Server,基础系列 2核4GB
简介: 本文介绍了MySQL中redo日志和undo日志的主要内容:1. redo日志的意义:确保事务提交后数据不丢失,通过记录修改操作并在系统宕机后重做日志恢复数据。2. redo日志文件构成:记录表空间号、数据页号、偏移量及修改内容。3. redo日志写入机制:redo日志先写入Redo Log Buffer,再批量刷入磁盘文件,减少随机写以提高性能。4. Redo Log Buffer解析:描述Redo Log Buffer的内存结构及刷盘时机,如事务提交、Buffer过半或后台线程定时刷新。5. undo日志原理:用于事务回滚,记录插入、删除和更新前的数据状态,确保事务可完整回滚。

大纲

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。

 

相关实践学习
如何快速连接云数据库RDS MySQL
本场景介绍如何通过阿里云数据管理服务DMS快速连接云数据库RDS MySQL,然后进行数据表的CRUD操作。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助     相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
相关文章
|
24天前
|
自然语言处理 搜索推荐 关系型数据库
MySQL实现文档全文搜索,分词匹配多段落重排展示,知识库搜索原理分享
本文介绍了在文档管理系统中实现高效全文搜索的方案。为解决原有ES搜索引擎私有化部署复杂、运维成本高的问题,我们转而使用MySQL实现搜索功能。通过对用户输入预处理、数据库模糊匹配、结果分段与关键字标红等步骤,实现了精准且高效的搜索效果。目前方案适用于中小企业,未来将根据需求优化并可能重新引入专业搜索引擎以提升性能。
|
16天前
|
数据可视化 关系型数据库 MySQL
ELK实现nginx、mysql、http的日志可视化实验
通过本文的步骤,你可以成功配置ELK(Elasticsearch, Logstash, Kibana)来实现nginx、mysql和http日志的可视化。通过Kibana,你可以直观地查看和分析日志数据,从而更好地监控和管理系统。希望这些步骤能帮助你在实际项目中有效地利用ELK来处理日志数据。
183 90
|
14天前
|
存储 SQL 关系型数据库
mysql的undo log、redo log、bin log、buffer pool
MySQL的undo log、redo log、bin log和buffer pool是确保数据库高效、安全和可靠运行的关键组件。理解这些组件的工作原理和作用,对于优化数据库性能和保障数据安全具有重要意义。通过适当的配置和优化,可以显著提升MySQL的运行效率和数据可靠性。
36 16
|
13天前
|
存储 SQL 关系型数据库
mysql的undo log、redo log、bin log、buffer pool
MySQL的undo log、redo log、bin log和buffer pool是确保数据库高效、安全和可靠运行的关键组件。理解这些组件的工作原理和作用,对于优化数据库性能和保障数据安全具有重要意义。通过适当的配置和优化,可以显著提升MySQL的运行效率和数据可靠性。
24 4
|
1月前
|
关系型数据库 MySQL 数据库
MySQL日志
本文介绍了MySQL中三个重要的日志:binlog、redolog和undolog。binlog记录数据库更改操作,支持数据恢复、复制和审计;redolog保证事务的原子性和持久性,实现crash-safe;undolog用于事务回滚及MVCC的实现。每个日志都有其独特的作用和应用场景,确保数据库的稳定性和数据一致性。
|
12天前
|
SQL 存储 关系型数据库
简单聊聊MySQL的三大日志(Redo Log、Binlog和Undo Log)各有什么区别
在MySQL数据库管理中,理解Redo Log(重做日志)、Binlog(二进制日志)和Undo Log(回滚日志)至关重要。Redo Log确保数据持久性和崩溃恢复;Binlog用于主从复制和数据恢复,记录逻辑操作;Undo Log支持事务的原子性和隔离性,实现回滚与MVCC。三者协同工作,保障事务ACID特性。文章还详细解析了日志写入流程及可能的异常情况,帮助深入理解数据库日志机制。
|
6天前
|
关系型数据库 MySQL 数据库连接
docker拉取MySQL后数据库连接失败解决方案
通过以上方法,可以解决Docker中拉取MySQL镜像后数据库连接失败的常见问题。关键步骤包括确保容器正确启动、配置正确的环境变量、合理设置网络和权限,以及检查主机防火墙设置等。通过逐步排查,可以快速定位并解决连接问题,确保MySQL服务的正常使用。
114 82
|
1天前
|
关系型数据库 MySQL Java
【YashanDB知识库】原生mysql驱动配置连接崖山数据库
【YashanDB知识库】原生mysql驱动配置连接崖山数据库
【YashanDB知识库】原生mysql驱动配置连接崖山数据库
|
2月前
|
关系型数据库 MySQL 数据库连接
数据库连接工具连接mysql提示:“Host ‘172.23.0.1‘ is not allowed to connect to this MySQL server“
docker-compose部署mysql8服务后,连接时提示不允许连接问题解决
|
9天前
|
消息中间件 缓存 NoSQL
缓存与数据库的一致性方案,Redis与Mysql一致性方案,大厂P8的终极方案(图解+秒懂+史上最全)
缓存与数据库的一致性方案,Redis与Mysql一致性方案,大厂P8的终极方案(图解+秒懂+史上最全)

相关产品

  • 云数据库 RDS MySQL 版