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

【MySql】数据库Redo日志介绍

目录

1. 为什么需要redo日志

2. redo日志的好处、特点

3. redo的组成

4. redo的整体流程

5. redo log的刷盘策略

6. 不同刷盘策略演示​编辑

7. 写入redo log buffer 过程


事务有4种特性:原子性、一致性、隔离性和持久性。那么事务的四种特性到底是基于什么机制实现呢?

  • 事务的隔离性由锁机制实现。
  • 而事务的原子性、一致性和持久性由事务的 redo 日志和undo 日志来保证。

REDO LOG 称为重做日志,提供再写入操作,恢复提交事务修改的页操作,用来保证事务的持久性。

UNDO LOG 称为回滚日志,回滚行记录到某个特定版本,用来保证事务的原子性、一致性。

有的DBA或许会认为 UNDO 是 REDO 的逆过程,其实不然。

  • redo log: 是存储引擎层(innodb)生成的日志,记录的是 物理级别 上的页修改操作,比如页号 xxx、偏移量 yyy 写入了’zzz"数据。主要为了保证数据的可靠性;
  • undo log: 是存储引擎层(innodb)生成的日志,记录的是 逻辑操作 日志,比如对某一行数据进行了INSERT语句操作,那么 undo log就记录一条与之相反的DELETE操作。主要用于 事务的回滚(undo log 记录的是每个修改操作的 逆操作)和 一致性非锁定读 (undo log 回滚行记录到某种特定的版本.--MVCC,即多版本并发控制)。

1. 为什么需要redo日志

一方面,缓冲池可以帮助我们消除CPU和磁盘之间的鸿沟,checkpoint机制可以保证数据的最终落盘,然而由于checkpoint 并不是每次变更的时候就触发的,而是master线程隔一段时间去处理的。所以最坏的情况就是事务提交后,刚写完缓冲池,数据库宕机了,那么这段数据就是丢失的,无法恢复。

另一方面,事务包含持久性的特性,就是说对于一个已经提交的事务,在事务提交后即使系统发生了崩溃,这个事务对数据库中所做的更改也不能丢失。

那么如何保证这个持久性呢? 一个简单的做法:在事务提交完成之前把该事务所修改的所有页面都刷新到磁盘,但是这个简单粗暴的做法有些问题:

修改量与刷新磁盘工作量严重不成比例

有时候我们仅仅修改了某个页面中的一个字节,但是我们知道在lnnoDB中是以页为单位来进行磁盘10的,也就是说我们在该事务提交时不得不将一个完整的页面从内存中刷新到磁盘,我们又知道一个页面默认是16KB大小,只修改一个字节就要刷新16KB的数据到磁盘上显然是太小题大做了。

随机I0刷新较慢

一个事务可能包含很多语句,即使是一条语句  也可能修改许多页面,假如该事务修改的这些页面可能并不相邻,这就意味着在将某个事务修改的Bufer Pool中的页面 刷新到磁盘 时,需要进行很多的 随机I0,随机I0比顺序I0要慢,尤其对于传统的机械硬盘来说。

另一个解决的思路:我们只是想让已经提交了的事务对数据库中数据所做的修改永久生效,即使后来系统崩溃,在重启后也能把这种修改恢复出来。所以我们其实没有必要在每次事务提交时就把该事务在内存中修改过的全部页面刷新到磁盘,只需要把修改了哪些东西记录一下就好。比如,某个事务将系统表空间中第10号页面中偏移量为100 处的那个字节的值 1 改成2 。我们只需要记录一下:将第0号表空间的10号页面的偏移量为100处的值更新为 2 。

2. redo日志的好处、特点

1. 好处

  • redo日志降低了刷盘频率
  • redo日志占用的空间非常小

存储表空间ID、页号、偏移量以及需要更新的值,所需的存储空间是很小的,刷盘快。

2. 特点

redo日志是顺序写入磁盘的

在执行事务的过程中,每执行一条语句,就可能产生若干条redo日志,这些日志是按照产生的顺序写入磁盘的
也就是使用顺序10,效率比随机IO快。

事务执行过程中,redo log不断记录

redo log 跟bin log的区别,redolog是存储引擎层产生的,而bin log是数据库层产生的。假设一个事务,对表做10万行的记录插入,在这个过程中,一直不断的往redolog顺序记录,而binlog不会记录,直到这个事务提交,才会一次写入到bin log文件中。

3. redo的组成

Redo log可以简单分为以下两个部分:

重做日志的缓冲 (redo log buffer) ,保存在内存中,是易失的。

在服务器启动时就向操作系统申请了一大片称之为redo log bufer的 连续内存 空间,翻译成中文就是redo日志缓冲区。这片内存空间被划分成若干个连续的redo log block。一个redo log block占用 512字节 大小。

参数设置:innodb_log_buffer_size:

redo log buffer 大小,默认16M ,最大值是4096M,最小值为1M。

重做日志文件 (redo log file) ,保存在硬盘中,是持久的。

4. redo的整体流程

以一个更新事务为例,redo log 流转过程,如下图所示:

第1步:先将原始数据从磁盘中读入内存中来,修改数据的内存拷贝

第2步:生成一条重做日志并写入redo log buffer,记录的是数据被修改后的值

第3步:当事务commit时,将redo log buffer中的内容刷新到 redo log file,对 redo log file采用追加写的方式

第4步:定期将内存中修改的数据刷新到磁盘中

体会:
Write-Ahead Log(预先日志持久化):在持久化一个数据页之前,先将内存中相应的日志页持久化。

5. redo log的刷盘策略

redo log的写入并不是直接写入磁盘的,InnoDB引擎会在写redo log的时候先写redo log buffer,之后以一定的频率刷入到真正的redo log file 中。这里的一定频率怎么看待呢?这就是我们要说的刷盘策略。

注意,redo log buffer刷盘到redo log file的过程并不是真正的刷到磁盘中去,只是刷入到文件系统缓存(page cache)中去(这是现代操作系统为了提高文件写入效率做的一个优化),真正的写入会交给系统自己来决定(比如page cache足够大了)。那么对于InnoDB来说就存在一个问题,如果交给系统来同步,同样如果系统宕机,那么数据也丢失了(虽然整个系统宕机的概率还是比较小的)。

针对这种情况,InnoDB给出innodb_flush_log_at_trx_commit 参数,该参数控制 commit提交事务
时,如何将 redo log buffer 中的日志刷新到 redo log file 中。它支持三种策略:

  • 设置为0 :表示每次事务提交时不进行刷盘操作。(系统默认master thread每隔1s进行一次重做日志的同步)
  • 设置为1 :表示每次事务提交时都将进行同步,刷盘操作( 默认值
  • 设置为2 :表示每次事务提交时都只把 redo log buffer 内容写入 page cache,不进行同步。由os自己决定什么时候同步到磁盘文件。

另外,InnoDB 存储引擎有一个后台线程,每隔1 秒,就会把 redo log buffer 中的内容写到文件系统缓存(page cache), 然后调用刷盘操作。

也就是说,一个没有提交事务的 redo log 记录,也可能会刷盘。因为在事务执行过程 redo log记录是会写入redo log buffer 中,这些 redo log 记录会被 后台线程 刷盘。

除了后台线程每秒1次的轮询操作,还有一种情况,当redo log buffer 占用的空间即将达到
innodb_1og_buffer_size(这个参数默认是16M)的一半的时候,后台线程会主动刷盘。

6. 不同刷盘策略演示

小结: innodb_flush_log_at_trx_commit=1

1时,只要事务提交成功,redo log记录就一定在硬盘里,不会有任何数据丢失。

如果事务执行期间 MySQL挂了或宕机,这部分日志丢了,但是事务并没有提交,所以日志丢了也不会有损失。可以保证ACID的D,数据绝对不会丢失,但是 效率最差的。

建议使用默认值,虽然操作系统宕机的概率理论小于数据库宕机的概率,但是一般既然使用了事务,那么数据的安全相对来说更重要些。

小结: innodb_flush_log_at_trx_commit=2

2时,只要事务提交成功,redo 1ogbuffer中的内容只写入文件系统缓存(page cache)

如果仅仅只是 MySQL 挂了不会有任何数据丢失,但是操作系统宕机可能会有1秒数据的丢失,这种情况下无法满足ACID中的D。但是数值2 肯定是效率最高的。

小结: innodb_flush_log_at_trx_commit=0

为8时,master thread中每1秒进行一次重做日志的fsync操作,因此实例 crash 最多丢失1秒钟内的事务,(master thread是负责将缓冲池中的数据异步刷新到磁盘,保证数据的一致性)

数值0的话,是一种折中的做法,它的!0效率理论是高于1的,低于2的,这种策略也有丢失数据的风险,也无法保证D。

7. 写入redo log buffer 过程

1. 补充概念:Mini-Transaction

一个事务可以包含若干条语句,每一条语句其实是由若干个mtr 组成,每一个mtr 又可以包含若干条redo日志,画个图表示它们的关系就是这样:

2. redo 日志写入log buffer

log buffer 中写入redo日志的过程是顺序的,也就是先往前边的block中写,当该block的空闲空间用完之后再往下一个block中写。当我们想往 log buffer 中写入redo日志时,第一个遇到的问题就是应该写在哪个block的哪个偏移量处,所以 InnoDB 的设计者特意提供了一个称之为 buf_free 的全局变量,该变量指明后续写入的redo日志应该写入到 log buffer 中的哪个位置,如图所示:

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

  • 事务 T1 的两个 mtr分别称为 mtr_T1_1mtr_T1_2
  • 事务 T2 的两个 mtr分别称为 mtr_T2_1mtr_T2_2

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

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

有的mtr产生的redo日志量非常大,比如 mtr_t1_2产生的redo日志占用空间比较大,占用了3个block来存储。

3. redo log block的结构图

一个redo log block是由 日志头、日志体、日志尾组成。日志 头占用12字节,日志尾占用8字节,所以一个block真正能存储的数据就是512-12-8=492字节,

 


http://www.kler.cn/a/534449.html

相关文章:

  • Java进阶学习之路
  • HTML排版标签、语义化标签、块级和行内元素详解
  • 【HarmonyOS之旅】基于ArkTS开发(二) -> UI开发三
  • 【Numpy核心编程攻略:Python数据处理、分析详解与科学计算】3.1 NumPy图像大小调整实战
  • Linux: 网络基础
  • 了解比特币
  • Slint的学习
  • 文本生图的提示词prompt和参数如何设置(基于Animagine XL V3.1)
  • 2025.2.5总结
  • Deepseek v3R1 学习笔记
  • 孟加拉国_行政边界省市边界arcgis数据shp格式wgs84坐标
  • 网络爬虫js逆向之某音乐平台案例
  • input 超出maxlength限制后,输入框变红
  • 9-收纳的知识
  • LabVIEW自定义测量参数怎么设置?
  • 基于springboot的体质测试数据分析及可视化设计
  • 教程 | i.MX RT1180 ECAT_digital_io DEMO 搭建(一)
  • 2025.2.5
  • 【分布式】服务端高并发分布式结构演进
  • C#面试常考随笔15:C#的GC原理是什么?
  • 【蓝桥杯—单片机】第十一届省赛真题代码题解题笔记 | 省赛 | 真题 | 代码题 | 刷题 | 笔记
  • leetcode_680 验证回文串
  • 除了淘宝开放平台的 API,还有哪些方式可以获取淘宝商品详情信息数据?
  • Android 13.0 系统默认手势导航时设置导航栏高度为1dp功能实现
  • DeepSeek R1技术报告关键解析(7/10):多阶段训练策略,如何优化 AI 的推理能力
  • 【自学笔记】Agent的重点知识点-持续更新