数据库通常借助日志来实现事务,常见的有undo log、redo log,undo/redo log都能保证事务特性,undolog实现事务原子性,redolog实现事务的持久性。

为了最大程度避免数据写入时io瓶颈带来的性能问题,MySQL采用了这样一种缓存机制:当query修改数据库内数据时,InnoDB先将该数据从磁盘读取到内存中,修改内存中的数据拷贝,并将该修改行为持久化到磁盘上的事务日志(先写redo log buffer,再定期批量写入),而不是每次都直接将修改过的数据记录到硬盘内,等事务日志持久化完成之后,内存中的脏数据可以慢慢刷回磁盘,称之为Write-Ahead Logging。事务日志采用的是追加写入,顺序io会带来更好的性能优势。

为了避免脏数据刷回磁盘过程中,掉电或系统故障带来的数据丢失问题,InnoDB采用事务日志(redo log)来解决该问题。

一、先简单了解几个概念

数据库数据存放的文件称为data file;

日志文件称为log file;

数据库数据是有缓存的,如果没有缓存,每次都写或者读物理disk,那性能就太低下了。数据库数据的缓存称为data buffer,日志(redo)缓存称为log buffer。

内存缓冲池

buffer pool如果mysql不用内存缓冲池,每次读写数据时,都需要访问磁盘,必定会大大增加I/O请求,导致效率低下。所以Innodb引擎在读写数据时,把相应的数据和索引载入到内存中的缓冲池(buffer pool)中,一定程度的提高了数据读写的速度。

buffer pool:占最大块内存,用来存放各种数据的缓存包括有索引页、数据页、undo页、插入缓冲、自适应哈希索引、innodb存储的锁信息、数据字典信息等。工作方式总是将数据库文件按页(每页16k)读取到缓冲池,然后按最近最少使用(lru)的算法来保留在缓冲池中的缓存数据。如果数据库文件需要修改,总是首先修改在缓存池中的页(发生修改后即为脏页dirty page),然后再按照一定的频率将缓冲池的脏页刷新到文件。

表空间

表空间可看做是InnoDB存储引擎逻辑结构的最高层。 表空间文件:InnoDB默认的表空间文件为ibdata1。

  • 段:表空间由各个段组成,常见的段有数据段、索引段、回滚段(undo log段)等。

  • 区:由64个连续的页组成,每个页大小为16kb,即每个区大小为1MB。

  • 页:每页16kb,且不能更改。常见的页类型有:数据页、Undo页、系统页、事务数据页、插入缓冲位图页、插入缓冲空闲列表页、未压缩的二进制大对象页、压缩的二进制大对象页。

 redo log 和undo log

  为了满足事务的持久性,防止buffer pool数据丢失,innodb引入了redo log。为了满足事务的原子性,innodb引入了undo log。

二、undo log

Undo log 是为了实现事务的原子性。还用Undo Log来实现多版本并发控制(简称:MVCC)。

delete/update操作的内部机制

当事务提交的时候,innodb不会立即删除undo log,因为后续还可能会用到undo log,如隔离级别为repeatable read时,事务读取的都是开启事务时的最新提交行版本,只要该事务不结束,该行版本就不能删除,即undo log不能删除。

但是在事务提交的时候,会将该事务对应的undo log放入到删除列表中,未来通过purge来删除。并且提交事务时,还会判断undo log分配的页是否可以重用,如果可以重用,则会分配给后面来的事务,避免为每个独立的事务分配独立的undo log页而浪费存储空间和性能。

通过undo log记录delete和update操作的结果发现:(insert操作无需分析,就是插入行而已)

  • delete操作实际上不会直接删除,而是将delete对象打上delete flag,标记为删除,最终的删除操作是purge线程完成的。
  • update分为两种情况:update的列是否是主键列。
  • 如果不是主键列,在undo log中直接反向记录是如何update的。即update是直接进行的。
  • 如果是主键列,update分两部执行:先删除该行,再插入一行目标行。

①事务的原子性

  事务的所有操作,要么全部完成,要不都不做,不能只做一半。如果在执行的过程中发生了错误,要回到事务开始时的状态,所有的操作都要回滚。

②原理 
  Undo Log的原理很简单,为了满足事务的原子性,在操作任何数据之前,首先将数据备份到一个地方(这个存储数据备份的地方称为Undo Log)。然后进行数据的修改。如果出现了错误或者用户执行了ROLLBACK语句,系统可以利用Undo Log中的备份将数据恢复到事务开始之前的状态。

假设有A、B两个数据,值分别为1,2。 进行+2的事务操作。 
A.事务开始. 
B.记录A=1到undo log. 
C.修改A=3. 
D.记录B=2到undo log. 
E.修改B=4. 
F.将undo log写到磁盘。 
G.将数据写到磁盘。 
H.事务提交 
这里有一个隐含的前提条件:‘数据都是先读到内存中,然后修改内存中的数据,最后将数据写回磁盘’。

之所以能同时保证原子性和持久化,是因为以下特点: 
A. 更新数据前记录Undo log。 
B. 为了保证持久性,必须将数据在事务提交前写到磁盘。只要事务成功提交,数据必然已经持久化。 
C. Undo log必须先于数据持久化到磁盘。如果在G,H之间系统崩溃,undo log是完整的,可以用来回滚事务。 
D. 如果在A-F之间系统崩溃,因为数据没有持久化到磁盘。所以磁盘上的数据还是保持在事务开始前的状态。 
缺点:每个事务提交前将数据和Undo Log写入磁盘,这样会导致大量的磁盘IO,因此性能很低。

三、Redo Log

redo log就是保存执行的SQL语句到一个指定的Log文件,当mysql执行数据恢复时,重新执行redo log记录的SQL操作即可。引入buffer pool会导致更新的数据不会实时持久化到磁盘,当系统崩溃时,虽然buffer pool中的数据丢失,数据没有持久化,但是系统可以根据Redo Log的内容,将所有数据恢复到最新的状态。redo log在磁盘上作为一个独立的文件存在。默认情况下会有两个文件,名称分别为 ib_logfile0和ib_logfile1。

参数innodb_log_file_size指定了redo log的大小;innodb_log_file_in_group指定了redo log的数量,默认为2; innodb_log_group_home_dir指定了redo log所在路径。

innodb_additional_mem_pool_size = 100M
innodb_buffer_pool_size = 128M
innodb_data_home_dir = /home/mysql/local/mysql/var
innodb_data_file_path = ibdata1:1G:autoextend
innodb_file_io_threads = 4
innodb_thread_concurrency = 16
innodb_flush_log_at_trx_commit = 1
innodb_log_buffer_size = 8M
innodb_log_file_size = 128M
innodb_log_file_in_group = 2
innodb_log_group_home_dir = /home/mysql/local/mysql/var

为了满足事务的原子性,在操作任何数据之前,首先将数据备份到Undo Log,然后进行数据的修改。如果出现了错误或者用户执行了ROLLBACK语句,系统可以利用Undo Log中的备份将数据恢复到事务开始之前的状态。与redo log不同的是,磁盘上不存在单独的undo log文件,它存放在数据库内部的一个特殊段(segment)中,这称为undo段(undo segment),undo段位于共享表空间内。

Innodb为每行记录都实现了三个隐藏字段:

  • 6字节的事务ID(DB_TRX_ID)
  • 7字节的回滚指针(DB_ROLL_PTR)
  • 隐藏的ID

redo log的记录内容

undo log和 redo log本身是分开的。innodb的undo log是记录在数据文件(ibd)中的,而且innodb将undo log的内容看作是数据,因此对undo log本身的操作(如向undo log中插入一条undo记录等),都会记录redo log。undo log可以不必立即持久化到磁盘上。即便丢失了,也可以通过redo log将其恢复。因此当插入一条记录时:

  1. 向undo log中插入一条undo log记录。
  2. 向redo log中插入一条”插入undo log记录“的redo log记录。
  3. 插入数据。
  4. 向redo log中插入一条”insert”的redo log记录。

redo log的io性能

为了保证Redo Log能够有比较好的IO性能,InnoDB 的 Redo Log的设计有以下几个特点:

  1. 尽量保持Redo Log存储在一段连续的空间上。因此在系统第一次启动时就会将日志文件的空间完全分配。以顺序追加的方式记录Redo Log。
  2. 批量写入日志。日志并不是直接写入文件,而是先写入redo log buffer,然后每秒钟将buffer中数据一并写入磁盘
  3. 并发的事务共享Redo Log的存储空间,它们的Redo Log按语句的执行顺序,依次交替的记录在一起,以减少日志占用的空间。
  4. Redo Log上只进行顺序追加的操作,当一个事务需要回滚时,它的Redo Log记录也不会从Redo Log中删除掉。

①原理

  和Undo Log相反,Redo Log记录的是新数据的备份。在事务提交前,只要将Redo Log持久化即可,不需要将数据持久化。当系统崩溃时,虽然数据没有持久化,但是Redo Log已经持久化。系统可以根据Redo Log的内容,将所有数据恢复到最新的状态。

②Undo + Redo事务的简化过程

A.事务开始. 
B.记录A=1到undo log. 
C.修改A=3. 
D.记录A=3到redo log. 
E.记录B=2到undo log. 
F.修改B=4. 
G.记录B=4到redo log. 
H.将redo log写入磁盘。 
I.事务提交

四、小结

A-G的过程是在内存中进行的,相应的操作记录在redo log buffer(B&E),redo log buffer(E&G)中,事务执行结果(此时未提交)也存在db buffer中(C&F),buffer满了就写入磁盘当中,如果buffer存储的事务数量都是1个,也就意味着是将日志立即刷入磁盘,那么数据的一致性很好保证。如果存储多个的话,是一次事务完成就会先将redo log同步到磁盘当中并有一个状态位来记录是否提交,再去真正的提交事务,将db buffer 中的数据同步到DB的磁盘当中去。要保证在db buffer中的内容写入磁盘数据库文件之前,应当把log buffer的内容写入磁盘日志文件。这种方式可以减少磁盘IO,增加吞吐量。 不过,这种方式适用于一致性要求不高的情景。因为如果出现断电等系统故障,log buffer、db buffer中的完成的事务还没同步到磁盘会丢失。 像银行这种要求事务较高的一致性,就一定要保证每次事务都要记录到磁盘中,如果服务器down了的时候去redo log中恢复,重做一次已经提交的事务。

五、redo & undo log的作用

  • 数据持久化

    buffer pool中维护一个按脏页修改先后顺序排列的链表,叫flush_list。根据flush_list中页的顺序刷数据到持久存储。按页面最早一次被修改的顺序排列。正常情况下,dirty page什么时候flush到磁盘上呢?

    1. 当redo空间占满时,将会将部分dirty page flush到disk上,然后释放部分redo log。
    2. 当需要在Buffer pool分配一个page,但是已经满了,这时候必须 flush dirty pages to disk。一般地,可以通过启动参数 innodb_max_dirty_pages_pct控制这种情况,当buffer pool中的dirty page到达这个比例的时候,把dirty page flush到disk中。
    3. 检测到系统空闲的时候,会flush。
  • 数据恢复

    随着时间的积累,Redo Log会变的很大。如果每次都从第一条记录开始恢复,恢复的过程就会很慢,从而无法被容忍。为了减少恢复的时间,就引入了Checkpoint机制。假设在某个时间点,所有的脏页都被刷新到了磁盘上。这个时间点之前的所有Redo Log就不需要重做了。系统记录下这个时间点时redo log的结尾位置作为checkpoint。在进行恢复时,从这个checkpoint的位置开始即可。Checkpoint点之前的日志也就不再需要了,可以被删除掉。

六、恢复(Recovery)

恢复策略 
  前面说到未提交的事务和回滚了的事务也会记录Redo Log,因此在进行恢复时,这些事务要进行特殊的处理.有2种不同的恢复策略:

A. 进行恢复时,只重做已经提交了的事务。(返回给客户端的是已经提交一定保证数据的可恢复持久性) 
B. 进行恢复时,重做所有事务包括未提交的事务和回滚了的事务。然后通过Undo Log回滚那些未提交的事务。比如在B-E过程中down机了,那么恢复时根据undo log去重新模拟当时的情景(但是如果log buffer的空间很大,log没有同步到磁盘这个过程就没有办法来进行,同时由于事务没有提交,返回给客户端的值是未提交成功,所以也没有关系)

InnoDB事务日志(redo log 和 undo log)详解的更多相关文章

  1. 详细分析MySQL事务日志(redo log和undo log)

    innodb事务日志包括redo log和undo log.redo log是重做日志,提供前滚操作,undo log是回滚日志,提供回滚操作. undo log不是redo log的逆向过程,其实它 ...

  2. 详细分析MySQL事务日志(redo log和undo log) 表明了为何mysql不会丢数据

    innodb事务日志包括redo log和undo log.redo log是重做日志,提供前滚操作,undo log是回滚日志,提供回滚操作. undo log不是redo log的逆向过程,其实它 ...

  3. 【MySQL (六) | 详细分析MySQL事务日志redo log】

    Reference:  https://www.cnblogs.com/f-ck-need-u/archive/2018/05/08/9010872.html 引言 为了最大程度避免数据写入时 IO ...

  4. mysql事务(一)——redo log与undo log

    数据事务 即支持ACID四大特性. A:atomicity          原子性——事务中所有操作要么全部执行成功,要么全部执行失败,回滚到初始状态 C:consistency     一致性—— ...

  5. InnoDB事务之redo log工作原理

    Reference:https://time.geekbang.org/column/article/121710 InnoDB是一个事务性的存储引擎,而InnoDB的事务实现是基于事务日志redo ...

  6. 必须了解的mysql三大日志-binlog、redo log和undo log

    日志是 mysql 数据库的重要组成部分,记录着数据库运行期间各种状态信息.mysql日志主要包括错误日志.查询日志.慢查询日志.事务日志.二进制日志几大类.作为开发,我们重点需要关注的是二进制日志( ...

  7. MySQL日志系统bin log、redo log和undo log

    MySQL日志系统bin log.redo log和undo log   今人不见古时月,今月曾经照古人. 简介:日志是MySQL数据库的重要组成部分,记录着数据库运行期间各种状态信息,主要包括错误日 ...

  8. 【Mysql】三大日志 redo log、bin log、undo log

    @ 目录 redo log(物理日志\重做日志) binlog(逻辑日志/归档日志) update语句执行流程 Uodolog(回滚日志/重做日志) undo log+redo log保证持久性 re ...

  9. 日志:Redo Log 和 Undo Log

    本篇文章主要介绍 Redo Log 和 Undo Log: 利用 Redo Log 和 Undo Log 实现本地事务的原子性.持久性 Redo Log 的写回策略 Redo Log Buffer 的 ...

随机推荐

  1. 服务端调用接口API利器之HttpClient

    前言 之前有介绍过HttpClient作为爬虫的简单使用,那么今天在简单的介绍一下它的另一个用途:在服务端调用接口API进行交互.之所以整理这个呢,是因为前几天在测试云之家待办消息接口的时候,有使用云 ...

  2. hive 数据导入

    Hive的几种常见的数据导入方式这里介绍四种:(1).从本地文件系统中导入数据到Hive表:(2).从HDFS上导入数据到Hive表:(3).从别的表中查询出相应的数据并导入到Hive表中:(4).在 ...

  3. ADO.NET操作MySQL数据库

    前言 ADO.NET包括5大对象,分别是Connection.Command.DataReader.DataSet.DataAdapter,使用ADO.NET访问数据库有两个步骤:建立数据库连接.读取 ...

  4. Android 不同分辨率下调整界面

    Android Settings中有修改Disaply size的界面,通过修改Display size,能够修改屏幕分辨率. 由于修改了屏幕分辨率,有可能导致同一界面在不同的分辨率下显示出错(内容显 ...

  5. 堆中的路径(MOOC)

    将一系列给定数字插入一个初始为空的小顶堆H[].随后对任意给定的下标i,打印从H[i]到根结点的路径. 输入格式: 每组测试第1行包含2个正整数N和M(≤),分别是插入元素的个数.以及需要打印的路径条 ...

  6. 各web服务器的特点和优势

    1.Tomcat 和 Jetty 面向java语言 天生就是重量级的web服务器.性能一般 2.IIS 只能在windows平台运行,windows作为服务器在稳定性与其他一些性能上不如类unix操作 ...

  7. 自然语言处理 - 如何通俗地理解TFIDF?

    本博客属个人学习笔记,如有疏漏,欢迎在评论留言指出~转载请注明. 在自然语言处理中,TFIDF常常被人提及.很多材料都提及TFIDF中的“普遍重要性”,但很少有材料去简单解释其中的原理.TFIDF其实 ...

  8. Python Requests库入门——应用实例-百度、360搜索关键词提交

    百度的关键词接口: http://www.baidu.com/s?wd=keyword 360的关键词接口: http://www.so.com/s?q=keyword keyword就是需要查找的关 ...

  9. “Hello World!”团队第七次Scrum立会

    "Hello world!"团队召开第七次Scrum立会.博客内容: 1.会议时间 2.会议成员 3.会议地点 4.会议内容 5.Todo list 6.会议照片 7.燃尽图 一. ...

  10. HDU 1121 Complete the Sequence 差分

    题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=1121 Complete the Sequence Time Limit: 3000/1000 MS ...