图解InnoDB事务实现原理|Redo Log&Undo Log

2,374 阅读6分钟

小知识,大挑战!本文正在参与“程序员必备小知识”创作活动

前言:

对于Mysql事务我们都知道事务具有ACID四个特性,分别为:

  • 原子性,
  • 一致性,
  • 隔离性,
  • 持久性。 基于以上四个特性,我们可以总结出事务 多个操作要么一起成功,要么一起失败,事务提交后,进行落盘存储,接下来我们来看一下InnoDB是如何实现事务的;

对于Innodb它主要由俩个事务日志文件redoLog和undoLog来保证事务的原子性,一致性,持久性;隔离性由锁来控制 如间隙锁,排它锁;

Redo Log(重做日志,提供前滚操作):

是什么?

redolog是InnoDB里用来记录事务提交的物理日志文件,记录的是数据页的物理修改,而不是某一行或某几行修改成怎样怎样,主要用来恢复提交后的物理数据页(恢复数据页,且只能恢复到最后一次提交的位置)。

事务提交后RedoLog做了什么?

在每次进行写数据的时候都会发生IO,对于InnoDB来说每次修改一次数据都发生IO在性能上肯定是不被允许的,所以加入了事务日志缓存这个概念,这就是redolog_buffer(日志缓冲区),每次事务日志的写入并不会直接写入到文件中,而是会写入到缓冲区中,在一定事件的触发下,才会将缓冲区内的数据写入到日志文件中。也就是说,一个写操作在InnoDB引擎内部发生的事情其实是这样的:

写操作 -->redoLog操作-->写入redolog buffer -->写入redolog file -->本地落盘

RedoLog重做日志主要是用来实现Mysql事务特性里的的持久性主要由俩部分组成:

  • redo Buffer 重做日志缓冲(内存)
  • redo File 重做日志文件(磁盘)

从上可以看出redoBuffer是存在内存里的这样也就意味着redoBuffer肯定是高性能的但是同时它也是易丢失的,在机器故障时会出现内存文件的丢失,而redoFile是存在磁盘里的说明在写磁盘的时候会产生IO代表着它在存储时性能较差但是数据则是持久化的;

详解:

在概念上,innodb通过force log at commit机制实现事务的持久性,即在事务提交的时候,必须先将该事务的所有事务日志写入到磁盘上的redo log file和undo log file中进行持久化。 为了确保每次日志都能写入到事务日志文件中,在每次将log buffer中的日志写入日志文件的过程中都会调用一次操作系统的fsync操作(即fsync()系统调用)。调用fsync()的作用就是将buffer中的日志刷到磁盘上的log file中。

图片.png

对于fsync这个操作用户是可以干预的,因为每次提交事务都执行一次fsync,是比较影响数据库性能。通过innodb_flush_log_at_trx_commit可以来控制redo log刷新到磁盘的策略。

  • innodb_flush_log_at_trx_commit=1(默认)

当设置为1的时候,事务每次提交都会将log buffer中的日志写入os buffer并调用fsync()刷到log file中。这种方式即使系统崩溃也不会丢失任何数据,但是因为每次提交都写入磁盘,IO的性能较差。

  • innodb_flush_log_at_trx_commit=0

当设置为0的时候,事务提交时不会将log buffer中日志写入到os buffer,而是每秒写入os buffer并调用fsync()写入到log file中。也就是说设置为0时是(大约)每秒刷新写入到磁盘中的,当系统崩溃,会丢失1秒钟的数据。

  • innodb_flush_log_at_trx_commit=2

当设置为2的时候,每次提交都仅写入到os buffer,然后是每秒调用fsync()将os buffer中的日志写入到log file中。

图片.png

Undo Log(回滚日志,提供回滚操作)

是什么?

undoLog是InnoDB提供的回滚日志,它的作用是用来提供事务的回滚能力,以及多个行版本控制(MVCC),用来回滚行记录到某个版本,undoLog一般是逻辑日志,根据每行记录进行记录;

与RedoLog相比二者都算是用来提供数据恢复的日志。不同的是redoLog是物理日志,而undoLog是逻辑日志,比如我们执行了一条update更新操作,undoLog就会将update的反向操作记录下来,而redoLog则只会记录修改后的数据值。并且undoLog本身也需要持久化支持,所以undoLog也会产生redoLog。

详解:

UndoLog它主要提供了如下两个功能:

  • 实现事务回滚
  • 实现MVCC

undolog的落盘流程可以看上文的第一个图片 初始数据行: 图片.png 如上图1~5是其对应的数据。后面三个隐含字段分别对应该行的事务号和回滚指针;

事务1更改该行的各字段的值: 图片.png

  1. 用排他锁锁定该行
  2. 记录redo log
  3. 把该行修改前的值写到undo log
  4. 修改当前行的值,填写事务编号,使回滚指针指向undo log中的修改前的行。 事务2修改该行的值: 图片.png 与事务一执行的流程相同,但是在undoLog中有有两行记录,并且通过回滚指针连在一起

当执行rollback时,就可以从undo log中的逻辑记录读取到相应的内容并进行回滚。有时候应用到行版本控制的时候,也是通过undo log来实现的:当读取的某一行被其他事务锁定时,它可以从undo log中分析出该行记录以前的数据是什么,从而提供该行版本信息,让用户实现非锁定一致性读取。

在InnoDB里有这么几个概念 页,区,段,表空间,而段分为这么几个

  • 数据段:存储数据
  • 索引段:存储索引
  • 回滚段:存储回滚日志 Innodb就是使用回滚段来管理undoLog的

MVCC

MVCC通常是通过保存数据在某个时间点的快照来实现的。这意味着一个事务无论运行多长时间,在同一个事务里能够看到数据一致的视图。根据事务开始的时间不同,同时也意味着在同一个时刻不同事务看到的相同表里的数据可能是不同的

  • 每行数据都存在一个版本,每次数据更新时都更新该版本。
  • 修改时Copy出当前版本随意修改,各个事务之间无干扰。
  • 保存时比较版本号,如果成功(commit),则覆盖原记录;失败则放弃copy(rollback)

ok!本期内容到此结束,你学废了吗,希望可以对大家有帮助,有不对的地方希望大家可以提出来的,共同成长;

整洁成就卓越代码,细节之中只有天地