MySQL日志专项之redo log和undo log介绍

目录
  • Redo Log
    • redo log刷盘策略
    • 其他参数
  • Undo Log
    • 回滚段与undo页
    • Undo类型
    • undo log的生命周期
    • 详细生成过程
    • undo log是如何回滚的
  • 扩展
    • bin log
    • 写入时机
    • binlog与redo log对比
  • 两阶段提交

Redo Log

REDO LOG称为重做日志 ,当MySQL服务器意外崩溃或者宕机后,保证已经提交的事务持久化到磁盘中(持久性)。

InnoDB是以页为单位去操作记录的,增删改查都会加载整个页到buffer pool中(磁盘->内存),事务中的修改操作并不是直接修改磁盘中的数据,而是先修改内存中buffer pool中的数据,后台线程每隔一段时间再异步刷新到磁盘中。

buffer pool:可存放索引、数据,可加速读写,直接在内存中操作数据页,有专门的线程去把buffer pool中的脏页写入磁盘。

为什么不直接修改磁盘中的数据?

因为直接修改磁盘数据的话,它是随机IO,修改的数据分布在磁盘中不同的位置,需要来回的查找,所以命中率低,消耗大,而且一个小小的修改就不得不将整个页刷新到磁盘,利用率低;

与之相对的是顺序IO,磁盘的数据分布在磁盘的一块,所以省去了查找的过程,节省寻道时间。

使用后台线程以一定的频率去刷新磁盘可以降低随机IO的频率,增加吞吐量,这是使用buffer pool的根本原因。

修改内存再异步同步到磁盘的问题:

因为buffer pool是在内存中的区域,系统意外崩溃的话数据有可能会丢失,有些脏数据可能会来不及刷新到磁盘,事务的持久性得不到保证。因此,引入了redo log。修改数据时,额外记录一次日志,内容是xx页xx偏移量发生了xx变化,当系统崩溃时可以根据日志内容进行恢复。

写日志和直接刷新磁盘的区别是:写日志是追加写入,顺序IO,速度更快,且写入的内容相对更小

redo log由两部分组成:

  1. redo log buffer(内存层面,默认16M,通过innodb_log_buffer_size参数可修改)
  2. redo log file(持久化的,磁盘层面)

修改操作大致过程:

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

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

第3步:默认在事务提交后将redo log buffer中的内容刷新到redo log file,对redo log file采用追加写的方式

第4步:定期将内存中修改的数据刷新到磁盘中(这里说的是那些还没及时被后台线程刷盘的脏数据)

通常所说的Write-Ahead Log(预先日志持久化)指的是在持久化一个数据页之前,先将内存中相应的日志页持久化。

redo log的好处:

  • 减少了磁盘刷新频率
  • redo log占用空间小
  • redo log写入速度快

redo log一定能保证事务的持久性吗?

不一定,这要根据redo log的刷盘策略决定,因为redo log buffer同样是在内存中,如果提交事务之后,redo log buffer还没来得及将数据刷新到redo log file进行持久化,此时发生宕机照样会丢失数据。如何解决?刷盘策略。

redo log刷盘策略

InnoDB中给出了innodb_flush_log_at_trx_commit参数控制redo log buffer刷新到redo log file时的三种策略:

  • 值为0:开启一个后台线程,每1s刷新一次到磁盘中,提交事务时就不需要进行刷新了
  • 值为1:commit时再进行同步刷新(默认值),真正保证数据的持久性
  • 值为2:commit的时候,只是刷新进os的内核缓冲区,具体的刷盘时机不确定

值为0的情况:

因为有1s的间隔,所以最坏情况下会丢失1秒的数据。

值为1的情况:

commit时需要先主动刷新redo log buffer到redo log file,如果中途宕机了,事务也就失败了,不会有任何损失,真正能保证事务的持久性。但是效率最差。

值为2的情况:是根据os决定。

可以调整为0或2提高事务的性能,但是丧失了ACID特性

其他参数

  • innodb_log_group_home_dir:指定 redo log文件组所在的路径,默认值为 ./ ,表示在数据库的数据目录下。MySQL的默认数据目录下默认有两个名为ib_logfile0和ib_logfile1的文件,log buffer中的日志默认情况下就是刷新到这两个磁盘文件中。
  • innodb_log_files_in_group:指明redo log file的个数,命名方式如:ib_logfile0,iblogfile1... iblogfilen。默认2个,最大100个。
  • innodb_log_file_size:单个 redo log 文件设置大小,默认值为 48M 。

Undo Log

undo log用于保证事务的原子性和一致性。作用有两个:①提供回滚操作 ②多版本控制MVVC

回滚操作

前面redo log中说过,后台线程会不定时的去刷新buffer pool中的数据到磁盘,但是如果该事务执行期间出现各种错误(宕机)或者执行rollback语句,那么前面刷进去的操作都是需要回滚的,保证原子性,undo log就是提供事务回滚的。

MVVC

当读取的某一行被其他事务锁定时,它可以从undo log中分析出该行记录以前的数据版本是怎样的,从而让用户能够读取到当前事务操作之前的数据——快照读。

快照读:SQL读取的数据是历史版本,不用加锁,普通的SELECT就是快照读。

undo log的组成部分:

  • 当insert记录的时候,必须将该记录的主键值记录下来,这样才可以回滚时删除该数据。
  • 当update记录的时候,必须将修改的旧值全部记录下来,回滚时更新为旧值即可。
  • 当delete的时候,必须将所有的记录都记录下来,回滚时再重新插入该内容的记录。

select操作不会产生undo log

回滚段与undo页

在InnoDB存储引擎中,undo log使用rollback segment回滚段进行存储,每隔回滚段包含了1024个undo log segment。 MySQL5.5之后,一共有128个回滚段。即总共可以记录128 * 1024个undo操作。

每个事务只会使用一个回滚段,一个回滚段在同一时刻可能会服务于多个事务。

事务提交后不能立即删除该undo log,可能有些事务会想要读取之前的数据版本(快照读)。所以事务提交时将undo log放入一个链表中,称为版本链,undo log的删除与否由一个称为purge的线程判断。

Undo类型

undo log分为:

insert undo log

因为insert操作的记录,只对事务本身可见,对其他事务不可见(这是事务隔离性的要求),故该undo log可以在事务提交后直接删除。不需要进行purge操作。

update undo log

update undo log记录的是对delete和update操作产生的undo log。该undo log可能需要提供MVCC机制,因此不能在事务提交时就进行删除。提交时放入undo log链表,等待purge线程进行最后的删除。

undo log的生命周期

假设有2个数值,分别为A=1和B=2,然后某个事务将A修改为3,B修改为4,修改过程可简化为:

1.begin
2.记录A=1到undo log
3.update A=3
4.记录A=3到redo log
5.记录B=2到undo log
6.update B=4
7.记录B=4到redo log
8.将redo log刷新到磁盘
9.commit

  • 在1-8步骤的任意一步系统宕机,事务未提交,该事务就不会对磁盘上的数据做任何影响。
  • 如果在8-9之间宕机,恢复之后可以选择回滚,也可以选择继续完成事务提交,因为此时redo log已经持久化。
  • 若在9之后系统宕机,内存映射中变更的数据还来不及刷回磁盘,那么系统恢复之后,可以根据redo log把数据刷回磁盘。

详细生成过程

对于InnoDB引擎来说,每个行记录除了记录本身的数据之外,还有几个隐藏的列:

  • DB_ROW_ID∶记录的主键id。
  • DB_TRX_ID:事务ID,当对某条记录发生修改时,就会将这个事务的Id记录其中。
  • DB_ROLL_PTR︰回滚指针,版本链中的指针。

当我们执行INSERT时:

begin;
INSERT INTO user (name) VALUES ('tom');

插入的数据都会生成一条insert undo log,并且数据的回滚指针会指向它。undo log会记录undo log的序号、插入主键的列和值...,那么在进行rollback的时候,通过主键直接把对应的数据删除即可。

当我们执行UPDATE时:

对于更新的操作会产生update undo log,并且会分更新主键的和不更新主键的,假设现在执行:

UPDATE user SET name='Sun' WHERE id=1;

这时会把新的undo log记录加入到版本链中,它的undo no是1,并且新的undo log的回滚指针会指向老的undo log (undo no=0)。

假设现在执行:

UPDATE user SET id=2 WHERE id=1;

对于更新主键的操作,会先把原来的数据deletemark标识打开,这时并没有真正的删除数据,真正的删除会交给清理线程去判断,然后在后面插入一条新的数据,新的数据也会产生undo log,并且undo log的序号会递增。

可以发现每次对数据的变更都会产生一个undo log,当一条记录被变更多次时,那么就会产生多条undo log,undo log记录的是变更前的日志,并且每个undo log的序号是递增的,那么当要回滚的时候,按照序号依次向前推,就可以找到我们的原始数据了。

undo log是如何回滚的

以上面的例子来说,假设执行rollback,那么对应的流程应该是这样:

1. 通过undo no=3的日志把id=2的数据删除

2. 通过undo no=2的日志把id=1的数据的deletemark还原成0

3. 通过undo no=1的日志把id=1的数据的name还原成Tom

4. 通过undo no=0的日志把id=1的数据删除

MySQL MVVC多版本并发控制

扩展

bin log

binlog即binary log,二进制日志文件,也叫作变更日志(update log)。它记录了数据库所有执行的更新语句。

binlog主要应用场景:

  • 数据恢复:如果MySQL意外停止,可以通过该日志进行恢复、备份
  • 数据复制:master把它的二进制日志传递给slaves来达到master-slave数据的一致性
show variables like '%log_bin%';

查看bin log日志:

mysqlbinlog -v "/var/lib/mysql/binlog/xxx.000002"

使用日志恢复数据:

mysqlbinlog [option] filename|mysql –uuser -ppass;

删除二进制日志:

PURGE {MASTER | BINARY} LOGS TO ‘指定日志文件名'
PURGE {MASTER | BINARY} LOGS BEFORE ‘指定日期'

写入时机

事务执行过程中,先把日志写到bin log cache ,事务提交的时候,再把binlog cache写到binlog文件中。因为一个事务的binlog不能被拆开,无论这个事务多大,也要确保一次性写入,所以系统会给每个线程分配一个块内存作为binlog cache。

binlog与redo log对比

  • redo log是物理日志,记录内容是“在xx数据页做了xx修改”,属于InnoDB存储引擎层产生的。
  • 而binlog是逻辑日志,记录内容是语句的原始逻辑,类似于给ID=2这一行的c字段加1,属于服务层。

两个侧重点也不同, redo log让InnoDB有了崩溃恢复的能力,binlog保证了MySQL集群架构的数据一致性。

两阶段提交

在执行更新语句过程,会记录redo log与binlog两块日志,以基本的事务为单位,redo log在事务执行过程中可以不断写入,而binlog只有在提交事务时才写入,所以redo log与binlog的写入时机不一样。

redo log与binlog两份日志之间的逻辑不一致,会出现什么问题?

以update语句为例,假设id=2的记录,字段c值是0,把字段c值更新成1,SQL语句为update T set c=1 where id=2。

假设执行过程中写完redo log日志后,binlog日志写期间发生了异常,会出现什么情况呢?

由于binlog没写完就异常,这时候binlog里面没有对应的修改记录。因此,之后用binlog日志恢复数据或者slave读取master的binlog时,就会少这一次更新,恢复出来的这一行c值是0,而原库因为redo log日志恢复,这一行c值是1,最终数据不一致。

为了解决两份日志之间的逻辑一致问题,InnoDB存储引擎使用两阶段提交方案。将redo log拆成了两个步骤prepare和commit,这就是两阶段提交。

让redo log和bin log最终的提交绑定到一起,前面说过的,事务commit时默认需要让redo log先同步完才算commit成功,所以如果绑定到一起的话,bin log也具有该特性了,就保证了数据不会丢失。

使用两阶段提交后,写入binlog时发生异常也不会有影响,因为MySQL根据redo log日志恢复数据时发现redo log还处于prepare阶段,并且没有对应binlog日志,就会提交失败,回滚数据。

另一个场景,redo log的commit阶段发生异常,那会不会回滚事务呢?

并不会回滚事务,它会执行上图框住的逻辑,虽然redo log是处于prepare阶段,但是能通过事务id找到对应的binlog日志,所以MySQL认为是完整的,就会提交事务恢复数据。

到此这篇关于MySQL日志专项之redo log和undo log介绍的文章就介绍到这了,更多相关MySQL redo log与undo log内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • MySQL事务日志(redo log和undo log)的详细分析

    目录 前言 1.redo log 1.1 redo log和二进制日志的区别 1.2 redo log的基本概念 1.3 日志块(log block) 1.4 log group和redo log file 1.5 redo log的格式 1.6 日志刷盘的规则 1.7 数据页刷盘的规则及checkpoint 1.8 LSN超详细分析 1.9 innodb的恢复行为 1.10 和redo log有关的几个变量 2.undo log 2.1 基本概念 2.2 undo log的存储方式 2.3 和

  • Mysql中undo、redo与binlog的区别浅析

    目录 前言 [undo log] [redo log] [binlog] 总结 前言 MySQL中有六种日志文件,分别是:重做日志(redo log).回滚日志(undo log).二进制日志(binlog).错误日志(errorlog).慢查询日志(slow query log).一般查询日志(general log),中继日志(relay log). 其中重做日志和回滚日志与事务操作息息相关,二进制日志也与事务操作有一定的关系,这三种日志,对理解MySQL中的事务操作有着重要的意义.   与

  • mysql日志文件之undo log和redo log

    目录 前言 1 undo 1.1 undo是什么 1.2 undo参数 1.3 undo空间管理 2 redo 2.1 redo是什么 2.2 redo 参数 2.3 redo 空间管理 3 undo及redo如何记录事务 3.1 Undo + Redo事务的简化过程 3.2  IO影响 3.3 恢复 总结 前言 在数据库系统中,既有存放数据的文件,也有存放日志的文件.日志在内存中也是有缓存Log buffer,也有磁盘文件log file,本文主要描述存放日志的文件. MySQL中的日志文件,

  • 详解MySQL 重做日志(redo log)与回滚日志(undo logo)

    前言: 前面文章讲述了 MySQL 系统中常见的几种日志,其实还有事务相关日志 redo log 和 undo log 没有介绍.相对于其他几种日志而言, redo log 和 undo log 是更加神秘,难以观测的.本篇文章将主要介绍这两类事务日志的作用及运维方法. 1.重做日志(redo log) 我们都知道,事务的四大特性里面有一个是 持久性 ,具体来说就是只要事务提交成功,那么对数据库做的修改就被永久保存下来了,不可能因为任何原因再回到原来的状态.那么 MySQL 是如何保证一致性的呢

  • MySQL系列之redo log、undo log和binlog详解

    事务的实现 redo log保证事务的持久性,undo log用来帮助事务回滚及MVCC的功能. InnoDB存储引擎体系结构 redo log Write Ahead Log策略 事务提交时,先写重做日志再修改页:当由于发生宕机而导致数据丢失时,就可以通过重做日志来完成数据的恢复. InnoDB首先将重做日志信息先放到重做日志缓存 按一定频率刷新到重做日志文件 重做日志文件: 在默认情况,InnoDB存储引擎的数据目录下会有两个名为ib_logfile1和ib_logfile2的文件.每个In

  • MySQL 撤销日志与重做日志(Undo Log与Redo Log)相关总结

    Undo Log 数据库事务开始之前,会将要修改的记录存放到 Undo 日志里,当事务回滚时或者数据库崩溃时,可以利用 Undo 日志,撤销未提交事务对数据库产生的影响. Undo Log产生和销毁 Undo Log在事务开始前产生:事务在提交时,并不会立刻删除undo log,innodb会将该事务对应的undo log放入到删除列表中,后面会通过后台线程purge thread进行回收处理. Undo Log属于逻辑日志,记录一个变化过程.例如执行一个delete,undolog会记录一个i

  • 基于Redo Log和Undo Log的MySQL崩溃恢复解析

    目录 MySQL崩溃恢复流程 1.黑盒下的更新数据流程 2.Redo Log & Undo Log 3.实现日志后的更新流程 3.流程中仍然存在的问题 4.基于2PC的一致性保障 5.验证2PC机制的可用性 MySQL崩溃恢复流程 Buffer Pool是MySQL内存结构中十分核心的一个组成,你可以先把它想象成一个黑盒子. 1.黑盒下的更新数据流程 当我们查询数据的时候,会先去Buffer Pool中查询.如果Buffer Pool中不存在,存储引擎会先将数据从磁盘加载到Buffer Pool

  • MySQL中的redo log和undo log日志详解

    MySQL日志系统中最重要的日志为重做日志redo log和归档日志bin log,后者为MySQL Server层的日志,前者为InnoDB存储引擎层的日志. 1 重做日志redo log 1.1 什么是redo log redo log用于保证事务的持久性,即ACID中的D. 持久性:指一个事务一旦被提交,它对数据库中数据的改变就是永久性的,接下来即使数据库发生故障也不应该对其有任何影响. redo log有两种类型,分别为物理重做日志和逻辑重做日志.在InnoDB中redo log大多数情

  • MySQL日志专项之redo log和undo log介绍

    目录 Redo Log redo log刷盘策略 其他参数 Undo Log 回滚段与undo页 Undo类型 undo log的生命周期 详细生成过程 undo log是如何回滚的 扩展 bin log 写入时机 binlog与redo log对比 两阶段提交 Redo Log REDO LOG称为重做日志 ,当MySQL服务器意外崩溃或者宕机后,保证已经提交的事务持久化到磁盘中(持久性). InnoDB是以页为单位去操作记录的,增删改查都会加载整个页到buffer pool中(磁盘->内存)

  • MySQL三大日志(binlog、redo log和undo log)图文详解

    目录 1.redo log redo log概述 刷盘时机 innodb_flush_log_at_trx_commit=0 innodb_flush_log_at_trx_commit=1 innodb_flush_log_at_trx_commit=2 日志文件组 2.binlog binlog 概述 记录格式 写入机制 刷盘时机 3.两阶段提交 4.undo log 5.总结 总结 1.redo log redo log概述 redo log(重做日志)是InnoDB存储引擎独有的,它让M

  • MySQL回滚日志(undo log)的作用和使用详解

    目录 一.undo log的概念 二.undo log的作用 三.undo log的存储机制 四.undo log的工作原理 五.undo log的相关参数 一.undo log的概念 undo log是mysql中比较重要的事务日志之一,顾名思义,undo log是一种用于撤销回退的日志,在事务没提交之前,MySQL会先记录更新前的数据到 undo log日志文件里面,当事务回滚时或者数据库崩溃时,可以利用 undo log来进行回退. 二.undo log的作用 在MySQL中,undo l

  • mysql日志系统redo log和bin log介绍

    首先,我们先来看看一次查询/更新语句流程图 本文会将重点放在执行器<->存储引擎之间的交互. mysql不是每次数据更改都立刻写到磁盘,而是会先将修改后的结果暂存在内存中,当一段时间后,再一次性将多个修改写到磁盘上,减少磁盘io成本,同时提高操作速度. mysql通过WAL(write-ahead logging)技术保证事务: 在同一个事务中,每当数据库进行修改数据操作时,将修改结果更新到内存后,会在redo log添加一行记录记录“需要在哪个数据页上做什么修改”,并将该记录状态置为prep

随机推荐