首页 > 数据库 >MySQL的redo与undo

MySQL的redo与undo

时间:2022-12-11 15:45:20浏览次数:65  
标签:事务 log undo file MySQL 日志 redo

1. MySQL事务特性

InnoDB 是一个事务性的存储引擎,事务有4种特性:原子性、一致性、隔离性和持久性

在事务中的操作,要么全部执行,要么全部不做,这就是事务的目的。

事务的四种特性到底是基于什么机制实现呢?
-事务的原子性、隔离性由锁机制实现
-事务的一致性和持久性由事务的 redo 日志和undo 日志来保证

redo log 是重做日志,提供再写入操作,实现事务的持久性;
undo log 是回滚日志,提供回滚操作,保证事务的一致性。

2. Redo log

在InnoDB存储引擎中,事务日志通过重做日志文件(redo log)和日志缓冲(InnoDB log buffer)实现。
当一个事务开始时,会记录事务的一个LSN(Log Sequence Number);
当事务执行时,会往InnoDB的日志缓冲中插入事务日志;
当事务提交时,必须先将日志缓冲写入磁盘,换言之,就是先写日志在写数据,这种方式称作预写日志WAL(write ahead logging)。
redo的作用:
记录的是尚未完成的操作,数据库崩溃则用其重做
redo的组成
Redo log可以简单分为以下两个部分:
保存在内存中重做日志的缓冲 (redo log buffer),是易失的
保存在硬盘中重做日志文件 (redo log file),是持久的
redo工作流程
InnoDB 的更新操作采用的是 Write Ahead Log (预先日志持久化)策略,即先写日志,再写入磁盘。
当一条记录更新时,redo流程大致如下
在内存更新数据后,会把更新后的记录写入到 redo log buffer 中。
第一步:InnoDB 会先把记录从硬盘读入内存
第二部:修改数据的内存拷贝
第三步:生成一条重做日志并写入redo log buffer,记录的是数据被修改后的值
第四步:当事务commit时,将redo log buffer中的内容刷新到 redo log file,对 redo log file采用追加写的方式
第五步:定期将内存中修改的数据刷新到磁盘中(注意注意注意,不是从redo log file刷入磁盘,而是从内存刷入磁盘,redo log file只在崩溃恢复数据时才用),
如果数据库崩溃,则依据redo log buffer、redo log file进行重做,恢复数据,这才是redo log file的价值所在
Write Ahead Log
redo是如何保证事务的持久性的呢?
  Force Log at Commit 机制
  即当事务commit提交时,innodb引擎先将 redo log buffer 写入到 redo log file 进行持久化,待事务的commit操作完成时才算完成。
  这种做法也被称为 Write-Ahead Log(预先日志持久化),在持久化一个数据页之前,先将内存中相应的日志页持久化。
* 为何不直接将修改的数据写入磁盘,而是要write ahead log呢?
  答案:用于崩溃恢复
  详解:
  undo日志是对原始数据的备份
  redo日志是对原始数据的修改
  原始数据的按照既定的数据结构存放在磁盘上,写入磁盘是要耗费巨大成本的,
  而写入redo相对容易一些,因为redo里毕竟只需要考虑存放改动的数据即可,所以内存数据写写入redo log file,
  然后内存数据才能写入磁盘,如此,在内存数据再写入磁盘时因为某种原因比如断电崩溃,那么还可以依据redo log file恢复数据。
* 如何保证每次修改的数据都能写入redo log file呢?

  # 储备知识1
  O_DIRECT选项是在Linux系统中的选项,使用该选项后,对文件进行直接IO操作,不经过文件系统缓存,直接写入磁盘

  # 储备知识2
  redo log又称之为重做日志,因重做日志打开并没有O_DIRECT选项,所以重做日志先写入到文件系统缓存,然后才会刷入硬盘,即
  Redo log buffer--->os cache(文件系统缓存)--->redo log file

  如果在刷入redo log file前断电,则会丢失文件系统缓存中数据,数据未写入redo log file,
  因为由内存写入redo log file在前,而由内存写入磁盘在后,所以redo log file写入失败,则数据丢失

  # 那如何保证每次的修改都记入日志文件redo log file呢???
  答案是fsync操作
  在每次将redo buffer写入os cache文件系统缓存后,InnoDB存储引擎都需要调用一次 fsync操作,保证立即由os cache文件系统缓存写入redo log file

  fsync是一种系统调用操作,其fsync的效率取决于磁盘的性能,因此磁盘的性能也影响了事务提交的性能,也就是数据库的性能。
* 脏页何时刷入磁盘呢?

  # 储备知识:脏页
  Buffer Pool 中更新的数据未刷新到磁盘中,该内存页我们称之为脏页。
  最终脏页的数据会刷新到磁盘中,将磁盘中的数据覆盖,这个过程与 redo log 不一定有关系。

  # 答案
  redo log 日志满了的情况下,会主动触发脏页刷新到磁盘
* 脏页只在redo log满的情况下才会刷入磁盘吗?

  答案:no,以下几种情况同样会触发脏页的刷新
  - 1、系统内存不足时,需要将一部分数据页淘汰掉,如果淘汰的是脏页,需要先将脏页同步到磁盘;
  - 2、MySQL 认为空闲的时间,这种情况没有性能问题;
  - 3、MySQL 正常关闭之前,会把所有的脏页刷入到磁盘,这种情况也没有性能问题。
* 脏页刷入会带来性能问题吗?

  在生产环境中,如果我们开启了慢 SQL 监控,你会发现偶尔会出现一些用时稍长的 SQL。
  这是因为脏页在刷新到磁盘时可能会给数据库带来性能开销,导致数据库操作抖动。
* 参数innodb_flush_log_at_trx_commit
  上面提到的Force Log at Commit机制就是靠InnoDB存储引擎提供的参数innodb_flush_log_at_trx_commit来控制的

  该参数控制 commit提交事务 时,如何将 redo log buffer 中的日志刷新到 redo log file 中。

  1、当设置参数为1时,(默认为1,建议),表示事务提交时必须调用一次 fsync 操作,最安全的配置,保障持久性
  2、当设置参数为2时,则在事务提交时只做 write 操作,只保证将redo log buffer写到系统的页面缓存中,不进行fsync操作,因此如果MySQL数据库宕机时 不会丢失事务,但操作系统宕机则可能丢失事务
  3、当设置参数为0时,表示事务提交时不进行写入redo log操作,这个操作仅在master thread 中完成,而在master thread中每1秒进行一次重做日志的fsync操作,因此实例 crash 最多丢失1秒钟内的事务。(master thread是负责将缓冲池中的数据异步刷新到磁盘,保证数据的一致性)
  拓展阅读
  我们需要注意的是 InnoDB 的 redo log 的大小是固定的,分别有多个日志文件采用循环方式组成一个循环闭环,当写到结尾时,会回到开头循环写日志。
  我们可以通过参数 innodb_log_files_in_group 和 innodb_log_file_size 配置日志文件数量和每个日志文件的大小。

3. Undo log

  重做日志记录了事务的行为,可以方便的通过其进行“重做”。

  但事务有时还需要撤销,这是就需要undo。

  undo与redo正好相反,undo是先写数据后记录undo log;

  事务对数据库进行修改时,会产生redo和undo,当有错误或rollback时,可以根据undo log将数据恢复到修改前的样子;
  undo存放在数据库内部的特殊段中(segment),undo段位于共享表空间内。

  undo并非对数据的物理恢复,而是逻辑恢复,例如插入了10万条数据,使表空间增加,undo后表空间并不会收缩;
  对于每条insert,undo是做相应的delete,对于update则是做了相反的update。
* undo即撤销还原。

  用于记录更改前的一份copy,在操作出错时,可以用于回滚、撤销还原,只将数据库逻辑地恢复到原来的样子

* undo日志记录了什么?

  比如有两个用户访问数据库,当然并发罗。A是更改,B是查询。

  -A更改还没有提交,B查询的话,数据肯定为历史数据,这个历史数据就是来源于UNDO段,

  -A更改未提交,需要回滚rollback,回滚rollback的数据也来至于UNDO段。

结论:为了并发时读一致性成功,那么DML操作,肯定先写UNDO段。
* undo的存储位置
  在InnoDB存储引擎中,undo存储在回滚段(Rollback Segment)中,每个回滚段记录了1024个undo log segment,而在每个undo log segment段中进行undo 页的申请,            
  -在5.6以前,Rollback Segment是在共享表空间里的,
  -5.6.3之后,可通过 innodb_undo_tablespace设置undo存储的位置。
undo的类型
在InnoDB存储引擎中,undo log分为:

insert undo log
update undo log
insert undo log是指在insert 操作中产生的undo log,因为insert操作的记录,只对事务本身可见,对其他事务不可见。故该undo log可以在事务提交后直接删除,不需要进行purge操作。

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

补充:purge线程两个主要作用是:清理undo页和清除page里面带有Delete_Bit标识的数据行。在InnoDB中,事务中的Delete操作实际上并不是真正的删除掉数据行,而是一种Delete Mark操作,在记录上标识Delete_Bit,而不删除记录。是一种"假删除",只是做了个标记,真正的删除工作需要后台purge线程去完成。

* undo log 是否是redo log的逆过程?
  undo log是逻辑日志,对事务回滚时,只是将数据库逻辑地恢复到原来的样子,
  而redo log是物理日志,记录的是数据页的物理变化,显然undo log不是redo log的逆过程。

redo & undo 过程

下面是redo log + undo log的简化过程,便于理解两种日志的过程:

假设有A、B两个数据,值分别为1,2
1. 事务开始
2. 记录A=1到undo log
3. 修改A=3
4. 记录A=3到 redo log
5. 记录B=2到 undo log
6. 修改B=4
7. 记录B=4到redo log
8. 将redo log写入磁盘
9. 事务提交
实际上,在insert/update/delete操作中,redo和undo分别记录的内容都不一样,量也不一样。在InnoDB内存中,一般的顺序如下:

写undo的redo
写undo
修改数据页
写Redo
因为,数据在没有commit前,是随时从内存中写入到表数据块的,属于脏数据。 数据库崩溃后即使使用redo流程进行redo操作,但是脏数据还在,脏数据怎么处理,就只能靠undo流程,使用undo数据块的旧数据覆盖了。

undo与redo的联系:但是不管是脏的还是旧的,都在redo日志中复制了一份。

1.undo是一种“数据文件datafile”,具有表空间,当然具有块block;
2.redo是一种“文件file”,没有表空间。
3.数据库在DML事务时,先创建undo
4.读一致性与一致性(scn相同)的区别
5.undo与rollback的区别:在undo(撤销还原流程)中会使用rollback(回滚)这个动作

参考
https://mp.weixin.qq.com/s/y0_9JWdoEYsJgR3MUVP4yQ
https://zhuanlan.zhihu.com/p/497876718

标签:事务,log,undo,file,MySQL,日志,redo
From: https://www.cnblogs.com/NetUSA/p/16973702.html

相关文章

  • 【MySQL】【数据库】sql的null不能用等号
    LeetCode584.寻找用户推荐人直达给定表customer,里面保存了所有客户信息和他们的推荐人。idnamereferee_id1WillNULL2JaneNULL3Alex24Bil......
  • mysql数据库和表的基础操作
    MySQL数据模型关系型数据库是建立在关系模型基础上的数据库,简单说,关系型数据库是由多张能互相连接的二维表组成的数据库 关系型数据库的优点:都是使用表结构,格式一致......
  • MySQL调优篇 | SQL调优实战
    【前言】经常有一些朋友向我咨询,如何写出高效的SQL,这不是三言两语能说得清的,索性认真来写一下,增删查改方面的知识我不再赘述,如果有基础薄弱的同学,可以好好的补一补再来看。......
  • 【mySQL】【数据库】union与or的区别--为什么建议用union代替or?
    LeetCode595.大的国家点击直达如果一个国家满足下述两个条件之一,则认为该国是大国:面积至少为300万平方公里(即,3000000km2),或者人口至少为2500万(即25000000)编写......
  • MySQL卸载的方法
    1、卸载电脑上的MySQL2、接着在电脑上搜索regedit.exe进入注册页面,按路径搜索HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\services\eventlog\Application\Mysql,删除Mysql注......
  • MySQL空间函数ST_Distance_Sphere()的使用
    MySQL空间函数ST_Distance_Sphere(g1,g2[,radius]):返回球体上两个点和/或多点之间的最小球面距离(以米为单位)官网(​​https://dev.mysql.com/doc/refman/5.7/en/spatial-......
  • MySQL 聚合函数初探
    MySQL提供了许多聚合函数,常见的如sum,avg,count,min,max等。那这些聚合函数在MySQL底层是怎么实现的?聚合函数(AggregateFunction)实现的大部分代码在item_sum.h和item_su......
  • MySQL8.0登录提示caching_sha2_password问题解决方法
    背景用​​docker​​构建mysql容器后连接遇到以下问题问题Authenticationplugin'caching_sha2_password'cannotbeloaded:dlopen(/usr/local/mysql/lib/plugin/cachin......
  • 深入理解 MySQL 的事务隔离级别和 MVCC 机制
    前言我们都知道MySQL实现了SQL标准中的四个隔离级别,但是具体是如何实现的可能还一知半解,本篇博客将会从代码层面讲解隔离级别的实现方式,下面进入正题。事务考虑这样......
  • MySQL
    MySQL排序我们知道从MySQL表中使用SQLSELECT语句来读取数据。如果我们需要对读取的数据进行排序,我们就可以使用MySQL的ORDERBY子句来设定你想按哪个字段哪种方......