前言

说到数据库事务,大家脑子里一定很容易蹦出一堆事务的相关知识,如事务的ACID特性,隔离级别,解决的问题(脏读,不可重复读,幻读)等等,但是可能很少有人真正的清楚事务的这些特性又是怎么实现的,为什么要有四个隔离级别。

在之前的文章我们已经了解了MySQL中事务的隔离性的实现原理,今天就继续来聊一聊MySQL持久性的实现原理。

当然MySQL博大精深,文章疏漏之处在所难免,欢迎批评指正。

说明

MySQL的事务实现逻辑是位于引擎层的,并且不是所有的引擎都支持事务的,下面的说明都是以InnoDB引擎为基准。

InnoDB读写数据原理

在往下学习之前,我们需要先来了解下InnoDB是怎么来读写数据的。我们知道数据库的数据都是存放在磁盘中的,然后我们也知道磁盘I/O的成本是很大的,如果每次读写数据都要访问磁盘,数据库的效率就会非常低。为了解决这个问题,InnoDB提供了 Buffer Pool 作为访问数据库数据的缓冲。

Buffer Pool 是位于内存的,包含了磁盘中部分数据页的映射。当需要读取数据时,InnoDB会首先尝试从Buffer Pool中读取,读取不到的话就会从磁盘读取后放入Buffer Pool;当写入数据时,会先写入Buffer Pool的页面,并把这样的页面标记为dirty,并放到专门的flush list上,这些修改的数据页会在后续某个时刻被刷新到磁盘中(这一过程称为刷脏,由其他后台线程负责) 。如下图所示:

这样设计的好处是可以把大量的磁盘I/O转成内存读写,并且把对一个页面的多次修改merge成一次I/O操作(刷脏一次刷入整个页面),避免每次读写操作都访问磁盘,从而大大提升了数据库的性能。

持久性定义

持久性是指事务一旦提交,它对数据库的改变就应该是永久性的,接下来的其他操作或故障不应该对本次事务的修改有任何影响。

通过前面的介绍,我们知道InnoDB使用 Buffer Pool 来提高读写的性能。但是 Buffer Pool 是在内存的,是易失性的,如果一个事务提交了事务后,MySQL突然宕机,且此时Buffer Pool中修改的数据还没有刷新到磁盘中的话,就会导致数据的丢失,事务的持久性就无法保证。

为了解决这个问题,InnoDB引入了 redo log来实现数据修改的持久化。当数据修改时,InnoDB除了修改Buffer Pool中的数据,还会在redo log 记录这次操作,并保证redo log早于对应的页面落盘(一般在事务提交的时候),也就是常说的WAL。若MySQL突然宕机了且还没有把数据刷回磁盘,重启后,MySQL会通过已经写入磁盘的redo log来恢复没有被刷新到磁盘的数据页。

实现原理:redo log

为了提高性能,和数据页类似,redo log 也包括两部分:一是内存中的日志缓冲(redo log buffer),该部分日志是易失性的;二是磁盘上的重做日志文件(redo log file),该部分日志是持久的。redo log是物理日志,记录的是数据库中物理页的情况 。

当数据发生修改时,InnoDB不仅会修改Buffer Pool中的数据,也会在redo log buffer记录这次操作;当事务提交时,会对redo log buffer进行刷盘,记录到redo log file中。如果MySQL宕机,重启时可以读取redo log file中的数据,对数据库进行恢复。这样就不需要每次提交事务都实时进行刷脏了。

写入过程

注意点:

  • 先修改Buffer Pool,后写 redo log buffer。
  • redo日志比数据页先写回磁盘:事务提交的时候,会把redo log buffer写入redo log file,写入成功才算提交成功(也有其他场景触发写入,这里就不展开了),而Buffer Pool的数据由后台线程在后续某个时刻写入磁盘。
  • 刷脏的时候一定会保证对应的redo log已经落盘了,也即是所谓的WAL(预写式日志),否则会有数据丢失的可能性。

好处

事务提交的时候,写入redo log 相比于直接刷脏的好处主要有三点:

  • 刷脏是随机I/O,但写redo log 是顺序I/O,顺序I/O可比随机I/O快多了,不需要。

  • 刷脏是以数据页(Page)为单位的,即使一个Page只有一点点修改也要整页写入;而redo log中只包含真正被修改的部分,数据量非常小,无效IO大大减少。

  • 刷脏的时候可能要刷很多页的数据,无法保证原子性(例如只写了一部分数据就失败了),而redo log buffer 向 redo log file 写log block,是按512个字节,也就是一个扇区的大小进行写入,扇区是写入的最小单位,因此可以保证写入是必定成功的。

先写redo log还是先修改数据

一次DML可能涉及到数据的修改和redo log的记录,那它们的执行顺序是怎么样的呢?网上的文章有的说先修改数据,后记录redo log,有的说先记录redo log,后改数据,那真实的情况是如何呢?

首先通过上面的说明我们知道,redo log buffer在事务提交的时候就会写入redo log file的,而刷脏则是在后续的某个时刻,所以可以确定的是先记录redo log,后修改data page(WAL当然是日志先写啦)。

那接下来的问题就是先写redo log buffer还是先修改Buffer Pool了。要了解这个问题,我们先要了解InnoDB中,一次DML的执行过程是怎么样的。一次DML的执行过程涉及了数据的修改,加锁,解锁,redo log的记录和undo log的记录等,也是需要保证原子性的,而InnoDB通过MTR(Mini-transactions)来保证一次DML操作的原子性。

首先来看MTR的定义:

An internal phase of InnoDB processing, when making changes at the physical level to internal data structures during DML operations. A Mini-transactions (mtr) has no notion of rollback; multiple Mini-transactionss can occur within a single transaction. Mini-transactionss write information to the redo log that is used during crash recovery. A Mini-transactions can also happen outside the context of a regular transaction, for example during purge processing by background threads.

见 https://dev.mysql.com/doc/refman/8.0/en/glossary.html

MTR 是一个短原子操作,不能回滚,因为它本身就是原子的。数据页的变更必须通过MTR,MTR 会把DML操作对数据页的修改记录到 redo log里。

下面来简单看下MTR的过程:

  • MTR初始化的时候会初始化一份 mtr_buf
  • 当修改数据时,在对内存Buffer Pool中的页面进行修改的同时,还会生成redo log record,保存在mtr_buf中
  • 在执行mtr_commit函数提交本MTR的时候,会将mtr_buf中的redo log record更新到redo log buffer中,同时将脏页添加到flush list,供后续刷脏使用。在log buffer中,每接收到496字节的log record,就将这组log record包装一个12字节的block header和一个4字节的block tailer,成为一个512字节的log block,方便刷盘的时候对齐512字节刷盘。

由此可见,InnoDB是先修改Buffer Pool,后写redo log buffer的。

恢复数据的过程

在任何情况下,InnoDB启动时都会尝试执行recovery操作。在恢复过程中,需要redo log参与,而如果还开启了binlog,那就还需要binlog、undo log的参与。因为有可能数据已经写入binlog了,但是redo log还没有刷盘的时候数据库就奔溃了(事务是InnoDB引擎的特性,修改了数据不一定提交了,而binlog是MySQL服务层的特性,修改数据就会记录了),这时候就需要redo log,binlog和undo log三者的参与来判断是否有还没提交的事务,未提交的事务进行回滚或者提交操作。

下面来简单说下仅利用redo log恢复数据的过程:

  • 启动InnoDB时,找到最近一次Checkpoint的位置,利用Checkpoint LSN去找大于该LSN的redo log进行日志恢复。
  • 如果中间恢复失败了也没影响,再次恢复的时候还是从上次保存成功的Checkpoint的位置继续恢复。

Recover过程:故障恢复包含三个阶段:Analysis,Redo和Undo。Analysis阶段的任务主要是利用Checkpoint及Log中的信息确认后续Redo和Undo阶段的操作范围,通过Log修正Checkpoint中记录的Dirty Page集合信息,并用其中涉及最小的LSN位置作为下一步Redo的开始位置RedoLSN。同时修正Checkpoint中记录的活跃事务集合(未提交事务),作为Undo过程的回滚对象;Redo阶段从Analysis获得的RedoLSN出发,重放所有的Log中的Redo内容,注意这里也包含了未Commit事务;最后Undo阶段对所有未提交事务利用Undo信息进行回滚,通过Log的PrevLSN可以顺序找到事务所有需要回滚的修改。

具体见 http://catkang.github.io/2019/01/16/crash-recovery.html

什么是LSN?

LSN也就是log sequence number,也日志的序列号,是一个单调递增的64位无符号整数。redo log和数据页都保存着LSN,可以用作数据恢复的依据。LSN更大的表示所引用的日志记录所描述的变化发生在更后面。

什么是Checkpoint?

Checkpoint表示一个保存点,在这个点之前的数据页的修改(log LSN<Checkpoint LSN)都已经写入磁盘文件了。InnoDB每次刷盘之后都会记录Checkpoint,把最新的redo log LSN 记录到Checkpoint LSN 里,方便恢复数据的时候作为起始点的判断。

版权声明

转载请注明作者和文章出处
作者: X先生
https://blog.csdn.net/u013314679/article/details/109389649

觉得不错的话请帮忙收藏点赞~

MySQL中事务的持久性实现原理相关推荐

  1. mysql 事物的持久性是指_详解MySQL中事务的持久性实现原理

    前言 说到数据库事务,大家脑子里一定很容易蹦出一堆事务的相关知识,如事务的ACID特性,隔离级别,解决的问题(脏读,不可重复读,幻读)等等,但是可能很少有人真正的清楚事务的这些特性又是怎么实现的,为什 ...

  2. mysql中decimal不能为空吗_程序员,知道Mysql中事务ACID的原理吗?

    点击上方"linkoffer", 选择关注公众号高薪职位第一时间送达 引言 照例,我们先来一个场景~ 面试官:"知道事务的四大特性么?" 你:"懂,A ...

  3. MySQL中事务四大特性的实现详解

    MySQL事务的四大特性的实现 基本概念 原子性实现 隔离性实现 已提交读 可重复读 持久性实现 日志文件刷新策略 基本概念 事务的四大特性ACID : 原子性Atomic : 事务的所有的SQL操作 ...

  4. MySQL 中事务的实现原理全解析

    在关系型数据库中,事务的重要性不言而喻,只要对数据库稍有了解的人都知道事务具有 ACID 四个基本属性,而我们不知道的可能就是数据库是如何实现这四个属性的:在这篇文章中,我们将对事务的实现进行分析,尝 ...

  5. limit实现原理 mysql_解读数据库:深入分析MySQL中事务以及MVCC的实现原理

    什么是事务 事务(Transaction)是由一系列对数据库中的数据进行访问与更新的操作所组成的一个程序执行单元. 在同一个事务中所进行的操作,要么都成功,要么就什么都不做.理想中的事务必须满足四大特 ...

  6. 14、mysql中事务的应用

    是什么 事务是一种保护连续操作同时满足(实现)的一种机制,用来保护数据的完整性,只适用于数据操作,不适用于结构操作,只有 innodb引擎的表具有事务安全的机制.就是说,在一个事务中做一系列的sql操 ...

  7. MySQL 中事务详解

    1.事务的概念 2.在MySQL中哪些存储引擎(表类型)支持事务哪些不支持 3.事务的四个属性 4.mysql事务的创建与存在周期 5.mysql行为 6.事务的孤立性和性能 7.mysql的伪事务 ...

  8. MySQL 中事务、事务隔离级别详解

    一.事务的概念 1.事务的概念 2.在mysql中哪些存储引擎(表类型)支持事务哪些不支持 3.事务的四个属性 4.mysql事务的创建与存在周期 5.mysql行为 6.事务的隔离性和性能 7.my ...

  9. Mysql中事务是什么?有什么用?

    通过这一篇文章让你彻底了解事务,文章当中提供了很多真实示例,供大家参考学习! 目录 一.什么是事务? 二.事务操作 1.没有事务会出现什么场景? 2.控制事务方式一(手动提交) 3.控制事务方式二(通 ...

最新文章

  1. 文巾解题 203. 移除链表元素
  2. WINDOWS SERVER 2003从入门到精通之DHCP中继代理
  3. 高手经验:一个新手的verilog学习经验
  4. 网络查找文档比自己电脑上还方便?
  5. python财务管理
  6. 34.Linux/Unix 系统编程手册(下) -- 进程组,会话和作业控制
  7. 不同平台安装python的方式一样吗_Python软件的正确安装方式
  8. 程序员必备的css工具,8个提高效率的CSS实用工具
  9. 【IoT】产品设计:如何写好硬件产品的需求文档?
  10. java枚举菜鸟教程_Java教程--枚举类型使用方法详细讲解
  11. 根据原图和对应的alpha图提取前景并且合成新图(基于python+opencv)
  12. Python数据分析学习系列 十四 数据分析案例
  13. TextView 设置显示省略号
  14. 盘点5款常用的网络拓扑图制作工具
  15. 关于Palantir——第二部分:本体(Ontology)
  16. iview表格中,鼠标滑过单元格展示提示信息
  17. Python实现邮箱自动群发工资条
  18. Android UI 之WaterFall瀑布流效果
  19. http://blog.csdn.net/hguisu/article/details/8836819
  20. 恒大健康:自称股东的FF员工提起集体诉讼 无理控告我们

热门文章

  1. 图解:什么是二叉堆?
  2. 移动硬盘数据恢复该如何进行?2个方法告诉你
  3. Thinkpad X200 换屏记
  4. cgb2111-day01
  5. Android自定义SeekBar,带开始值结束值和Thumb上方滑动的Text
  6. webstorm注册码
  7. 第48章 MDK的编译过程及文件类型全解—零死角玩转STM32-F429系列
  8. android 错误中英互译,中英文翻译器应用的官方Android版本v3.1.1
  9. Excel根据某一列的内容对另一列进行分组汇总
  10. 数字化门店| 旧衣回收店系统 | 智慧门店小程序开发教程