精华内容
下载资源
问答
  • 吃透MySQL(十一):undolog redolog binlog原理详细介绍

    千次阅读 热门讨论 2021-03-06 12:09:19
    一,Undo log Undo:意为取消,以撤销操作为目的,返回指定某个状态的操作。 Undo Log:数据库事务提交之前,会将事务修改数据的镜像(即修改前的旧版本)存放到 undo 日志里,当事务回滚时,或者数据库奔溃时,可以...


    在这里插入图片描述

    一,Undo log

    Undo:意为取消,以撤销操作为目的,返回指定某个状态的操作。

    Undo Log:数据库事务提交之前,会将事务修改数据的镜像(即修改前的旧版本)存放到 undo 日志里,当事务回滚时,或者数据库奔溃时ÿ

    展开全文
  • 这篇文章主要介绍了MySQL系列之redo logundo log和binlog详解,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下。事务的实现redo log保证事务的持久性,undo log用来...

    这篇文章主要介绍了MySQL系列之redo log、undo log和binlog详解,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下。

    事务的实现

    redo log保证事务的持久性,undo log用来帮助事务回滚及MVCC的功能。

    InnoDB存储引擎体系结构

    redo log:Write Ahead Log策略

    事务提交时,先写重做日志再修改页;当由于发生宕机而导致数据丢失时,就可以通过重做日志来完成数据的恢复。

    InnoDB首先将重做日志信息先放到重做日志缓存;

    然后,按一定频率刷新到重做日志文件。

    重做日志文件: 在默认情况,InnoDB存储引擎的数据目录下会有两个名为ib_logfile1和ib_logfile2的文件。每个InnoDB存储引擎至少有1个重做日志文件组(group),每个文件组下至少有2个重做日志文件。

    下面图一,很好说明重做日志组以循环写入方式运行,InnoDB存储引擎先写ib_logfile1,当达到文件最后时,会切换至重做日志文件ib_logfile2.

    而图2,增加一个OS Buffer,有助于理解fsync过程。

    关于log group,称为重做日志组,是一个逻辑上的概念。InnoDB存储引擎实际只有一个log group。

    log group中第一个redo log file,其前2KB部分保存4个512字节大小块:

    重做日志缓冲刷新到磁盘

    下面三种情况刷新:

    Master Thread每一秒将重做日志缓冲刷新到重做日志文件

    每个事务提交时会将重做日志缓冲刷新到重做日志文件

    当重做日志缓冲池剩余空间小于1/2时,重做日志刷新到重做日志文件

    补充上述三种情况第二种,触发写磁盘过程由参数innodb_flush_log_at_trx_commit控制,表示提交(commit)操作时,处理重做日志的方式。

    参数 innodb_flush_log_at_trx_commit 有效值有0、1、2

    0表示当提交事务时,并不将事务的重做日志写入磁盘上日志文件,而是等待主线程每秒刷新。

    1表示在执行commit时将重做日志缓冲同步写到磁盘,即伴有fsync的调用

    2表示将重做日志异步写到磁盘,即写到文件系统的缓存中。不保证commit时肯定会写入重做日志文件。

    0,当数据库发生宕机时,部分日志未刷新到磁盘,因此会丢失最后一段时间的事务。

    2,当操作系统宕机时,重启数据库后会丢失未从文件系统缓存刷新到重做日志文件那部分事务。

    下图有助于理解

    重做日志块

    在InnoDB存储引擎中,重做日志都是以512字节进行存储的。意味着重做日志缓存、重做日志文件都是以块(block)的方式进行保存的,每块512字节。

    重做日志头12字节,重做日志尾8字节,故每个重做日志块实际可以存储492字节。

    重做日志格式

    redo log是基于页的格式来记录的。默认情况下,innodb的页大小是16KB(由 innodb_page_size变量控制),一个页内可以存放非常多的log block(每个512字节),而log block中记录的又是数据页的变化。

    log body的格式分为4部分:

    redo_log_type:占用1个字节,表示redo log的日志类型。

    space:表示表空间的ID,采用压缩的方式后,占用的空间可能小于4字节。

    page_no:表示页的偏移量,同样是压缩过的。

    redo_log_body表示每个重做日志的数据部分,恢复时会调用相应的函数进行解析。例如insert语句和delete语句写入redo log的内容是不一样的。

    如下图,分别是insert和delete大致的记录方式。

    redo日志恢复

    下面 LSN (Log Sequence Number) 代表 checkpoint,当数据库在 LSN 为10000时发生宕机,恢复操作仅恢复LSN10000-LSN13000范围内日志

    undo log

    undo log的作用:

    undo是逻辑日志,只是将数据库逻辑地恢复到原来的样子;所有修改都被逻辑地取消了,但是数据结构和页本身在回滚之后可能不大相同。

    undo log有两个作用:提供回滚和多个行版本控制(MVCC)。

    InnoDB存储引擎回滚时,对于每个INSERT,会完成一个DELETE;对于每个DELETE,会执行一个INSERT;对于每个UPDATE,会执行一个相反的UPDATE,将修改前的行放回去。

    MVCC: 当用户读取一行记录时,若该记录已经被其他事务占用,当前事务可以通过undo读取之前的行版本信息,以此实现非锁定读取。

    undo log的存储方式:

    innodb存储引擎对undo的管理采用段的方式。rollback segment称为回滚段,每个回滚段中有1024个undo log segment。

    在以前老版本,只支持1个rollback segment,这样就只能记录1024个undo log segment。后来MySQL5.5可以支持128个rollback segment,即支持128*1024个undo操作,还可以通过变量 innodb_undo_logs (5.6版本以前该变量是 innodb_rollback_segments )自定义多少个rollback segment,默认值为128。

    undo log默认存放在共享表空间中。

    事务提交undo log处理过程

    当事务提交时,InnoDB存储引擎会做以下两件事:

    1、将undo log放入一个列表中,以供之后的purge使用,是否可以最终删除undo log及所在页由purge线程来判断

    2、判断undo log 所在的页是否可以重用,若可以,分配给下个事务使用

    当事务提交时,首先将undo log放入链表中,然后判断undo页的使用空间是否小于3/4,若是,则表示该undo页可以被重用,之后新的undo log记录在当前undo log的后面

    undo log分为:

    insert undo log

    update undo log

    因为事务隔离性,insert undo log对其他事务不可见,所以该undo log可以在事务提交后直接删除,不需要进行purge操作。

    update undo log记录的是对delete和update操作产生的undo log。该undo log可能需要提供MVCC机制,因此不能提交时就进行删除

    update分为两种情况:

    date的列如果不是主键列,在undo log中直接反向记录是如何update的。即update是直接进行的。

    update主键的操作可以分为两步:

    首先将原主键记录标记为已删除,因此需要产生一个类型为TRX_UNDO_DEL_MARK_REC的undo log

    之后插入一条新的记录,产生一个类型为TRX_UNDO_INSERT_MARK_REC的undo log

    InnoDB purge时,会先从history列表找undo log,然后再从undo page中找undo log;可以避免大量随机读取操作,从而提高purge效率。

    MVCC(多版本并发控制)

    MVCC其实就是在每一行记录后面增加两个隐藏列,记录创建版本号和删除版本号,而每一个事务在启动的时候,都有一个唯一的递增的版本号。

    MVCC只在REPEATABLE READ 和READ COMMITTED两个隔离级别下工作。读未提交不存在版本问题,序列化则对所有读取行加锁。

    示例:

    插入操作:记录的创建版本号就是事务版本号

    如插入一条记录,事务id假设是1,则创建版本号也是1

    idnamecreate versiondelete version

    1test1

    更新操作:先标记旧版本号为已删除,版本号就是当前版本号,再插入一条新的记录

    如事务2把name字段更新

    update table set name = 'new test' where id = 1;

    原来的记录被标记删除,删除版本号为2,并插入新记录,创建版本号为2

    idnamecreate versiondelete version

    1test12

    1new test2

    删除操作:把事务版本作为删除版本号

    如事务3把记录删除

    delete from table where id = 1;

    idnamecreate versiondelete version

    1test23

    查询操作

    需满足以下两个条件的记录才能被事务查询出来:

    InnoDB只查找版本早于当前事务版本的数据行

    行的删除版本要么未定义,要么大于当前版本号,这可以确保事务读取到的行,在事务未开始之前未被删除

    MVCC好处:减少锁的争用,提升性能

    binlog

    二进制文件概念及作用

    二进制文件(binary log)记录了对MySQL数据库执行更改的所有操作(不包含SELECT、SHOW等,因为对数据没有修改)

    二进制文件主要几种作用:

    恢复:某些数据的恢复需要二进制日志

    复制: 通过复制和执行二进制日志使一台远程的MySQL(slave)与另一台MySQL数据库(master)进行实时同步

    审计: 用户可以通过二进制日志中信息来进行审计,判断是否有对数据库进行注入的攻击

    二进制文件三个格式

    MySQL 5.1开始引入binlog_format参数,该参数可设值有STATEMENT、ROW和MIX

    STATEMENT: 二进制文件记录的是日志的逻辑SQL语句

    ROW:记录表的行更改情况。如果设置了ROW模式,可以将InnoDB事务隔离级别设为READ_COMMITTED,以获得更好的并发性

    MIX:MySQL默认采用STATEMENT格式进行二进制文件的记录,但在一些情况下会使用ROW,可能的情况有:

    表的存储引擎为NDB,这时对表DML操作都以ROW格式进行

    使用了UUID()、USER()、CURRENT_USER()、FOUND_ROWS()、ROW_COUNT()等不确定函数

    使用了INSERT DELAY语句

    使用了用户定义函数

    使用了临时表

    redo log和二进制文件区别

    (二进制文件用来进行POINT-IN-TIME(PIT))的恢复及主从复制环境的建立。

    二进制文件会记录所有与MySQL数据库有关的日志记录,包括InnoDB、MyISAM等其他存储引擎的日志。而InnoDB存储引擎的重做日志只记录有关该存储引擎本身的事务日志。

    记录的内容不同,无论用户将二进制日志文件记录的格式设为STATEMENT、ROW或MIXED,其记录的都是关于一个事务的具体操作内容,即该日志是逻辑日志。而InnoDB存储引擎的重做日志文件记录的是关于每个页的更改的物理情况。

    此外,写入的时间页不同,二进制日志文件仅再事务提交前进行提交,即只写磁盘一次,不论这时该事务多大。而在事务进行的过程中,却不断有重做日志条目(reod entry)被写入到重做日志文件中。

    group commit

    若事务为非只读事务,则每次事务提交时需要进行一次fsync操作,以此保证重做日志都已经写入磁盘。但磁盘fsync性能有限,为提高磁盘fsync效率,当前数据库都提供group commit功能,即一次可以刷新确保多个事务日志被写入文件。

    对InnoDB group commit,进行两阶段操作:

    1、修改内存中事务对应的信息,并且将日志写入重做日志缓冲

    2、调用fsync将确保日志都从重做日志缓冲写入磁盘

    InnoDB1.2前,开启二进制文件,group commit功能失效问题:

    开启二进制文件后,其步骤如下:

    1)当事务提交时,InnoDB存储引擎进行prepare操作

    2)MySQL数据库上层写入二进制文件

    3)InnoDB将日志写入重做日志文件

    a)修改内存中事务对应的信息,并将日志写入重做日志缓冲b)调用fsync将确保日志都从重做日志缓冲写入磁盘

    其中在保证MySQL数据库上层二进制文件的写入顺序,和InnoDB事务提交顺序一致,MySQL内部使用了prepare_commit_mutex锁,从而步骤3)中a)步不可以在其他事务执行步骤b)时进行,从而导致roup commit功能失效。

    解决方案便是 BLGC (Binary Log Group Commit)

    MySQL 5.6 BLGC实现方式分为三个阶段:

    Flush阶段:将每个事务的二进制文件写入内存

    Sync阶段:将内存中的二进制刷新到磁盘,若队列有多个事务,那么仅一次fsync操作就完成了二进制日志的写入,这就是BLGC

    Commit阶段:leader根据顺序调用存储引擎层事务提交,由于innodb本就支持group commit,所以解决了因为锁 prepare_commit_mutex 而导致的group commit失效问题。

    https://www.jb51.net/article/202911.htm


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

    日志是mysql数据库的重要组成部分,记录着数据库运行期间各种状态信息。mysql日志主要包括错误日志、查询日志、慢查询日志、事务日志、二进制日志几大类。作为开发,我们重点需要关注的是二进制日志(binlog)和事务日志(包括redo log和undo log),本文接下来会详细介绍这三种日志。

    binlog

    binlog用于记录数据库执行的写入性操作(不包括查询)信息,以二进制的形式保存在磁盘中。binlog是mysql的逻辑日志,并且由Server层进行记录,使用任何存储引擎的mysql数据库都会记录binlog日志。

    逻辑日志:可以简单理解为记录的就是sql语句

    物理日志:因为mysql数据最终是保存在数据页中的,物理日志记录的就是数据页变更

    binlog是通过追加的方式进行写入的,可以通过max_binlog_size参数设置每个binlog文件的大小,当文件大小达到给定值之后,会生成新的文件来保存日志。

    binlog使用场景

    在实际应用中,binlog的主要使用场景有两个,分别是主从复制数据恢复

    主从复制:在Master端开启binlog,然后将binlog发送到各个Slave端,Slave端重放binlog从而达到主从数据一致。

    数据恢复:通过使用mysqlbinlog工具来恢复数据。

    binlog刷盘时机

    对于InnoDB存储引擎而言,只有在事务提交时才会记录biglog,此时记录还在内存中,那么biglog是什么时候刷到磁盘中的呢?mysql通过sync_binlog参数控制biglog的刷盘时机,取值范围是0-N:

    0:不去强制要求,由系统自行判断何时写入磁盘;

    1:每次commit的时候都要将binlog写入磁盘;

    N:每N个事务,才会将binlog写入磁盘。

    从上面可以看出,sync_binlog最安全的是设置是1,这也是MySQL 5.7.7之后版本的默认值。但是设置一个大一些的值可以提升数据库性能,因此实际情况下也可以将值适当调大,牺牲一定的一致性来获取更好的性能。

    binlog日志格式

    binlog日志有三种格式,分别为STATMENT、ROW和MIXED。

    在 MySQL 5.7.7之前,默认的格式是STATEMENT,MySQL 5.7.7之后,默认值是ROW。日志格式通过binlog-format指定。

    STATMENT

    基于SQL语句的复制(statement-based replication, SBR),每一条会修改数据的sql语句会记录到binlog中

    优点:不需要记录每一行的变化,减少了binlog日志量,节约了IO, 从而提高了性能

    缺点:在某些情况下会导致主从数据不一致,比如执行sysdate()、slepp()等

    ROW

    基于行的复制(row-based replication, RBR),不记录每条sql语句的上下文信息,仅需记录哪条数据被修改了

    优点:不会出现某些特定情况下的存储过程、或function、或trigger的调用和触发无法被正确复制的问题

    缺点:会产生大量的日志,尤其是alter table的时候会让日志暴涨

    MIXED

    基于STATMENT和ROW两种模式的混合复制(mixed-based replication, MBR),一般的复制使用STATEMENT模式保存binlog,对于STATEMENT模式无法复制的操作使用ROW模式保存binlog

    redo log

    为什么需要redo log

    我们都知道,事务的四大特性里面有一个是持久性,具体来说就是只要事务提交成功,那么对数据库做的修改就被永久保存下来了,不可能因为任何原因再回到原来的状态。那么mysql是如何保证一致性的呢?最简单的做法是在每次事务提交的时候,将该事务涉及修改的数据页全部刷新到磁盘中。但是这么做会有严重的性能问题,主要体现在两个方面:

    因为Innodb是以页为单位进行磁盘交互的,而一个事务很可能只修改一个数据页里面的几个字节,这个时候将完整的数据页刷到磁盘的话,太浪费资源了!

    一个事务可能涉及修改多个数据页,并且这些数据页在物理上并不连续,使用随机IO写入性能太差!

    因此mysql设计了redo log,具体来说就是只记录事务对数据页做了哪些修改,这样就能完美地解决性能问题了(相对而言文件更小并且是顺序IO)。

    redo log基本概念

    redo log包括两部分:

    一个是内存中的日志缓冲(redo log buffer);

    另一个是磁盘上的日志文件(redo log file)。

    mysql每执行一条DML语句,先将记录写入redo log buffer,后续某个时间点再一次性将多个操作记录写到redo log file。

    这种先写日志,再写磁盘的技术就是MySQL里经常说到的WAL(Write-Ahead Logging) 技术。

    在计算机操作系统中,用户空间(user space)下的缓冲区数据一般情况下是无法直接写入磁盘的,中间必须经过操作系统内核空间(kernel space)缓冲区(OS Buffer)。因此,redo log buffer写入redo log file实际上是先写入OS Buffer,然后再通过系统调用fsync()将其刷到redo log file中,过程如下:

    mysql支持三种将redo log buffer写入redo log file的时机,可以通过innodb_flush_log_at_trx_commit参数配置,各参数值含义如下:

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

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

    2(实时写,延迟刷)每次提交都仅写入到os buffer,然后是每秒调用fsync()将os buffer中的日志写入到redo log file。

    redo log记录形式

    前面说过,redo log实际上记录数据页的变更,而这种变更记录是没必要全部保存,因此redo log实现上采用了大小固定,循环写入的方式,当写到结尾时,会回到开头循环写日志。如下图:

    在上图中,write pos表示redo log当前记录的LSN(逻辑序列号)位置,check point表示数据页更改记录刷盘后对应redo log所处的LSN(逻辑序列号)位置。write pos到check point之间的部分是redo log空着的部分,用于记录新的记录;check point到write pos之间是redo log待落盘的数据页更改记录。当write pos追上check point时,会先推动check point向前移动,空出位置再记录新的日志。

    同时我们很容易得知,在innodb中,既有redo log需要刷盘,还有数据页也需要刷盘,redo log存在的意义主要就是降低对数据页刷盘的要求

    启动innodb的时候,不管上次是正常关闭还是异常关闭,总是会进行恢复操作。因为redo log记录的是数据页的物理变化,因此恢复的时候速度比逻辑日志(如binlog)要快很多。

    重启innodb时,首先会检查磁盘中数据页的LSN,如果数据页的LSN小于日志中的LSN,则会从checkpoint开始恢复。

    还有一种情况,在宕机前正处于checkpoint的刷盘过程,且数据页的刷盘进度超过了日志页的刷盘进度,此时会出现数据页中记录的LSN大于日志中的LSN,这时超出日志进度的部分将不会重做,因为这本身就表示已经做过的事情,无需再重做。

    redo log与binlog区别

    文件大小redo log的大小是固定的。

    binlog可通过配置参数max_binlog_size设置每个binlog文件的大小。

    实现方式redo log是InnoDB引擎层实现的,并不是所有引擎都有。

    binlog是Server层实现的,所有引擎都可以使用 binlog日志。

    记录方式redo log 采用循环写的方式记录,当写到结尾时,会回到开头循环写日志。binlog 通过追加的方式记录,当文件大小大于给定值后,后续的日志会记录到新的文件上

    适用场景redo log适用于崩溃恢复(crash-safe)binlog适用于主从复制和数据恢复

    由binlog和redo log的区别可知:binlog日志只用于归档,只依靠binlog是没有crash-safe能力的。但只有redo log也不行,因为redo log是InnoDB特有的,且日志上的记录落盘后会被覆盖掉。因此需要binlog和redo log二者同时记录,才能保证当数据库发生宕机重启时,数据不会丢失。

    undo log

    数据库事务四大特性中有一个是原子性,具体来说就是 原子性是指对数据库的一系列操作,要么全部成功,要么全部失败,不可能出现部分成功的情况。实际上,原子性底层就是通过undo log实现的。undo log主要记录了数据的逻辑变化,比如一条INSERT语句,对应一条DELETE的undo log,对于每个UPDATE语句,对应一条相反的UPDATE的undo log,这样在发生错误时,就能回滚到事务之前的数据状态。同时,undo log也是MVCC(多版本并发控制)实现的关键,这部分内容在面试中的老大难-mysql事务和锁,一次性讲清楚!中有介绍,不再赘述。

    参考:

    https://juejin.im/post/6844903794073960455

    https://www.cnblogs.com/f-ck-need-u/archive/2018/05/08/9010872.html

    https://www.cnblogs.com/ivy-zheng/p/11094528.html

    https://yq.aliyun.com/articles/592937

    https://www.jianshu.com/p/5af73b203f2a

    https://www.jianshu.com/p/20e10ed721d0

    展开全文
  • 作为开发,我们重点需要关注的是二进制日志(binlog)事务日志(包括redo log和undo log),本文接下来会详细介绍这三种日志。 binlog binlog用于记录数据库执行的写入性操作(不包括查询)信息,以二进制的形式保存在...

    转自:https://juejin.cn/post/6860252224930070536

    日志是mysql数据库的重要组成部分,记录着数据库运行期间各种状态信息。mysql日志主要包括错误日志、查询日志、慢查询日志、事务日志、二进制日志几大类。作为开发,我们重点需要关注的是二进制日志(binlog)和事务日志(包括redo logundo log),本文接下来会详细介绍这三种日志。

    binlog

    binlog用于记录数据库执行的写入性操作(不包括查询)信息,以二进制的形式保存在磁盘中。binlogmysql的逻辑日志,并且由Server层进行记录,使用任何存储引擎的mysql数据库都会记录binlog日志。

    逻辑日志:可以简单理解为记录的就是sql语句

    物理日志:因为mysql数据最终是保存在数据页中的,物理日志记录的就是数据页变更

    binlog是通过追加的方式进行写入的,可以通过max_binlog_size参数设置每个binlog文件的大小,当文件大小达到给定值之后,会生成新的文件来保存日志。

    binlog使用场景

    在实际应用中,binlog的主要使用场景有两个,分别是主从复制数据恢复

    1. 主从复制:在Master端开启binlog,然后将binlog发送到各个Slave端,Slave端重放binlog从而达到主从数据一致。
    2. 数据恢复:通过使用mysqlbinlog工具来恢复数据。

    binlog刷盘时机

    对于InnoDB存储引擎而言,只有在事务提交时才会记录biglog,此时记录还在内存中,那么biglog是什么时候刷到磁盘中的呢?mysql通过sync_binlog参数控制biglog的刷盘时机,取值范围是0-N

    • 0:不去强制要求,由系统自行判断何时写入磁盘;
    • 1:每次commit的时候都要将binlog写入磁盘;
    • N:每N个事务,才会将binlog写入磁盘。

    从上面可以看出,sync_binlog最安全的是设置是1,这也是MySQL 5.7.7之后版本的默认值。但是设置一个大一些的值可以提升数据库性能,因此实际情况下也可以将值适当调大,牺牲一定的一致性来获取更好的性能。

    binlog日志格式

    binlog日志有三种格式,分别为STATMENTROWMIXED

    MySQL 5.7.7之前,默认的格式是STATEMENTMySQL 5.7.7之后,默认值是ROW。日志格式通过binlog-format指定。

    • STATMENT 基于SQL语句的复制(statement-based replication, SBR),每一条会修改数据的sql语句会记录到binlog。 优点:不需要记录每一行的变化,减少了binlog日志量,节约了IO, 从而提高了性能; 缺点:在某些情况下会导致主从数据不一致,比如执行sysdate()slepp()
    • ROW 基于行的复制(row-based replication, RBR),不记录每条sql语句的上下文信息,仅需记录哪条数据被修改了。 优点:不会出现某些特定情况下的存储过程、或function、或trigger的调用和触发无法被正确复制的问题; 缺点:会产生大量的日志,尤其是alter table的时候会让日志暴涨
    • MIXED 基于STATMENTROW两种模式的混合复制(mixed-based replication, MBR),一般的复制使用STATEMENT模式保存binlog,对于STATEMENT模式无法复制的操作使用ROW模式保存binlog

    redo log

    为什么需要redo log

    我们都知道,事务的四大特性里面有一个是持久性,具体来说就是只要事务提交成功,那么对数据库做的修改就被永久保存下来了,不可能因为任何原因再回到原来的状态。那么mysql是如何保证持久性的呢?最简单的做法是在每次事务提交的时候,将该事务涉及修改的数据页全部刷新到磁盘中。但是这么做会有严重的性能问题,主要体现在两个方面:

    1. 因为Innodb是以为单位进行磁盘交互的,而一个事务很可能只修改一个数据页里面的几个字节,这个时候将完整的数据页刷到磁盘的话,太浪费资源了!
    2. 一个事务可能涉及修改多个数据页,并且这些数据页在物理上并不连续,使用随机IO写入性能太差!

    因此mysql设计了redo log具体来说就是只记录事务对数据页做了哪些修改,这样就能完美地解决性能问题了(相对而言文件更小并且是顺序IO)。

    redo log基本概念

    redo log包括两部分:一个是内存中的日志缓冲(redo log buffer),另一个是磁盘上的日志文件(redo log file)。mysql每执行一条DML语句,先将记录写入redo log buffer,后续某个时间点再一次性将多个操作记录写到redo log file。这种先写日志,再写磁盘的技术就是MySQL里经常说到的WAL(Write-Ahead Logging) 技术。

    在计算机操作系统中,用户空间(user space)下的缓冲区数据一般情况下是无法直接写入磁盘的,中间必须经过操作系统内核空间(kernel space)缓冲区(OS Buffer)。因此,redo log buffer写入redo log file实际上是先写入OS Buffer,然后再通过系统调用fsync()将其刷到redo log file中,过程如下:

    mysql支持三种将redo log buffer写入redo log file的时机,可以通过innodb_flush_log_at_trx_commit参数配置,各参数值含义如下:

    参数值含义
    0(延迟写)事务提交时不会将redo log buffer中日志写入到os buffer,而是每秒写入os buffer并调用fsync()写入到redo log file中。也就是说设置为0时是(大约)每秒刷新写入到磁盘中的,当系统崩溃,会丢失1秒钟的数据。
    1(实时写,实时刷)事务每次提交都会将redo log buffer中的日志写入os buffer并调用fsync()刷到redo log file中。这种方式即使系统崩溃也不会丢失任何数据,但是因为每次提交都写入磁盘,IO的性能较差。
    2(实时写,延迟刷)每次提交都仅写入到os buffer,然后是每秒调用fsync()os buffer中的日志写入到redo log file

    redo log记录形式

    前面说过,redo log实际上记录数据页的变更,而这种变更记录是没必要全部保存,因此redo log实现上采用了大小固定,循环写入的方式,当写到结尾时,会回到开头循环写日志。如下图:

    同时我们很容易得知,在innodb中,既有redo log需要刷盘,还有数据页也需要刷盘,redo log存在的意义主要就是降低对数据页刷盘的要求。在上图中,write pos表示redo log当前记录的LSN(逻辑序列号)位置,check point表示数据页更改记录刷盘后对应redo log所处的LSN(逻辑序列号)位置。write poscheck point之间的部分是redo log空着的部分,用于记录新的记录;check pointwrite pos之间是redo log待落盘的数据页更改记录。当write pos追上check point时,会先推动check point向前移动,空出位置再记录新的日志。

    启动innodb的时候,不管上次是正常关闭还是异常关闭,总是会进行恢复操作。因为redo log记录的是数据页的物理变化,因此恢复的时候速度比逻辑日志(如binlog)要快很多。 重启innodb时,首先会检查磁盘中数据页的LSN,如果数据页的LSN小于日志中的LSN,则会从checkpoint开始恢复。 还有一种情况,在宕机前正处于checkpoint的刷盘过程,且数据页的刷盘进度超过了日志页的刷盘进度,此时会出现数据页中记录的LSN大于日志中的LSN,这时超出日志进度的部分将不会重做,因为这本身就表示已经做过的事情,无需再重做。

    redo log与binlog区别

     redo logbinlog
    文件大小redo log的大小是固定的。binlog可通过配置参数max_binlog_size设置每个binlog文件的大小。
    实现方式redo logInnoDB引擎层实现的,并不是所有引擎都有。binlogServer层实现的,所有引擎都可以使用 binlog日志
    记录方式redo log 采用循环写的方式记录,当写到结尾时,会回到开头循环写日志。binlog 通过追加的方式记录,当文件大小大于给定值后,后续的日志会记录到新的文件上
    适用场景redo log适用于崩溃恢复(crash-safe)binlog适用于主从复制和数据恢复

    binlogredo log的区别可知:binlog日志只用于归档,只依靠binlog是没有crash-safe能力的。但只有redo log也不行,因为redo logInnoDB特有的,且日志上的记录落盘后会被覆盖掉。因此需要binlogredo log二者同时记录,才能保证当数据库发生宕机重启时,数据不会丢失。

    undo log

    数据库事务四大特性中有一个是原子性,具体来说就是 原子性是指对数据库的一系列操作,要么全部成功,要么全部失败,不可能出现部分成功的情况。实际上,原子性底层就是通过undo log实现的。undo log主要记录了数据的逻辑变化,比如一条INSERT语句,对应一条DELETEundo log,对于每个UPDATE语句,对应一条相反的UPDATEundo log,这样在发生错误时,就能回滚到事务之前的数据状态。同时,undo log也是MVCC(多版本并发控制)实现的关键,这部分内容在面试中的老大难-mysql事务和锁,一次性讲清楚!中有介绍,不再赘述。

    展开全文
  • redo log 是物理日志,undo log binlog 是逻辑日志 binlog二进制日志是server层的无论MySQL用什么引擎,都会有的,主要是左主从复制,时间点恢复使用 redo log重做日志是InnoDB存储引擎层的,用来保证事务安全 ...
    • redo log 是物理日志,undo log 和 binlog 是逻辑日志
    • binlog二进制日志是server层的无论MySQL用什么引擎,都会有的,主要是左主从复制,时间点恢复使用
    • redo log重做日志是InnoDB存储引擎层的,用来保证事务安全
    • undo log回滚日志保存了事务发生之前的数据的一个版本,可以用于回滚,同时可以提供多版本并发控制下的读(MVCC),也即非锁定读

    crash-safe概念

    InnoDB 就可以保证即使数据库发生异常重启,之前提交的记录都不会丢失,这个能力称为 crash-safe。

    举个列子:当我们修改的时候,写完内存了(buffer),但数据还没真正写到磁盘的时候。此时我们的数据库挂了,我们可以对数据进行恢复

    redo log (重做日志)

    redo log 是物理日志,记载着每次在某个页上做了什么修改。写redo log也是需要写磁盘的,但它的好处就是顺序IO(我们都知道顺序IO比随机IO快非常多)。写入的速度很快

    生命周期

    1. 事务开始之后,就开始产生 redo log 日志了,在事务执行的过程中,redo log 开始逐步落盘
    2. 当对应事务的脏页写入到磁盘之后,redo log 的使命就完成了,它所占用的空间也就可以被覆盖了。
    3. InnoDB 的 redo log 是固定大小的,比如可以配置为一组 4 个文件,每个文件的大小是 1GB。从头开始写,写到末尾就又回到开头循环写

    file

    1. write pos 是当前记录的位置,一边写一边后移,写到第 3 号文件末尾后就回到 0 号文件开头。checkpoint 是当前要擦除的位置,也是往后推移并且循环的,擦除记录前要把记录更新到数据文件。
    2. write pos 和 checkpoint 之间的的部分,可以用来记录新的操作。如果 write pos 追上 checkpoint,表示“粉板”满了,这时候不能再执行新的更新,得停下来先擦掉一些记录,把 checkpoint 推进一下。

    存储内容

    redo log 包括两部分:

    • 一是内存中的日志缓冲(redo log buffer),该部分日志是易失性的;
    • 二是磁盘上的重做日志文件(redo log file),该部分日志是持久的,redo log 存储的是物理格式的日志,记录的是物理数据页面的修改信息,它是顺序写入 redo log file 中的。

    落盘方式(将 innodb 日志缓冲区的日志刷新到磁盘)

    1. Master Thread 每秒一次执行刷新 Innodb_log_buffer 到重做日志文件 
    2. 每个事务提交时会将重做日志刷新到重做日志文件
    3. 当重做日志缓存可用空间少于一半时,重做日志缓存被刷新到重做日志文件

    注意:

    1. 其实写redo log的时候,也会有buffer,是先写buffer,再真正落到磁盘中的。至于从buffer什么时候落磁盘,会有配置供我们配置。
    2. redo log 是 InnoDB 引擎特有的日志
    3. 持久性就是靠redo log来实现的(如果写入内存成功,但数据还没真正刷到磁盘,如果此时的数据库挂了,我们可以靠redo log来恢复内存的数据,这就实现了持久性)。

    undo log (回滚日志)

    u保存了事务发生之前的数据的一个版本,作用:

    1. 可以用于回滚
    2. 同时可以提供多版本并发控制下的读(MVCC),也即非锁定读

      生命周期

    3. 事务开始之前,将当前事务版本生成 undo log,undo log 也会产生 redo log 来保证 undo log 的可靠性。
    4. 事务提交之后,undo log 并不能立马被删除,而是放入待清理的链表
    5. 由 purge 线程判断是否有其它事务在使用 undo 段中表的上一个事务之前的版本信息,从而决定是否可以清理 undo log 的日志空间。

    存储内容

    undo log 存储的是逻辑格式的日志,保存了事务发生之前的上一个版本的数据,可以用于回滚。当一个旧的事务需要读取数据时,为了能读取到老版本的数据,需要顺着 undo 链找到满足其可见性的记录。

    存储位置

    默认情况下,undo 文件是保存在共享表空间的,也即 ibdatafile 文件中,当数据库中发生一些大的事务性操作的时候,要生成大量的 undo log 信息,这些信息全部保存在共享表空间中,因此共享表空间可能会变得很大,默认情况下,也就是 undo log 使用共享表空间的时候,被“撑大”的共享表空间是不会、也不能自动收缩的。因此,MySQL5.7 之后的“独立 undo 表空间”的配置就显得很有必要了。

    binlog (二进制日志)

    • binlog我们可以简单理解为:存储着每条变更的SQL语句
    • 可以通过binlog来对数据进行恢复
    • binlog 可以用于主从复制中,从库利用主库上的 binlog 进行重播,实现主从同步。用于数据库的基于时间点、位点等的还原操作。binlog 的模式分三种:Statement、Row、Mixed。

    bin-log三种模式

    Statement 模式

    每一条修改数据的 sql 都会记录到 master 的 binlog 中,slave 在复制的时候,sql 进程会解析成和原来在 master 端执行时的相同的 sql 再执行。

    • 优点:在 statement 模式下首先就是解决了 row 模式的缺点,不需要记录每一行数据的变化,从而减少了 binlog 的日志量,节省了 I/O 以及存储资源,提高性能。因为它只需要记录在 master 上执行的语句的细节以及执行语句的上下文信息。
    • 缺点:在 statement 模式下,由于它是记录的执行语句,所以,为了让这些语句在 slave 端也能正确执行,那么它还必须记录每条语句在执行的时候的一些相关信息,即上下文信息,以保证所有语句在 slave 端和在 master 端执行结果相同。另外就是,由于 MySQL 现在发展比较快,很多新功能不断的加入,使 MySQL 的复制遇到了不小的挑战,自然复制的时候涉及到越复杂的内容,bug 也就越容易出现。在statement 中,目前已经发现不少情况会造成 MySQL 的复制出现问题,主要是在修改数据的时候使用了某些特定的函数或者功能才会出现,比如:sleep() 函数在有些版本中就不能被正确复制,在存储过程中使用了 last_insert_id() 函数,可能会使 slave 和 master 上得到不一致的 id 等等。由于 row 模式是基于每一行来记录变化的,所以不会出现类似的问题。

    Row 模式

    日志中会记录每一行数据被修改的形式,然后在 slave 端再对相同的数据进行修改。row 模式只记录要修改的数据,只有 value,不会有 sql 多表关联的情况。

    • 优点:在 row 模式下,binlog 中可以不记录执行的 sql 语句的上下文相关的信息,仅仅只需要记录哪一条记录被修改了,修改成什么样了,所以 row 的日志内容会非常清楚的记录下每一行数据的修改细节,非常容易理解。而且不会出现某些特定情况下的存储过程和 function,以及 trigger 的调用和触发无法被正确复制问题。
    • 缺点:在 row 模式下,当所有执行语句记录到日志中的时候,都将以每行记录的修改来记录,这样可能会产生大量的日志内容。

    Mixed 模式

    从官方文档中看到,之前的 MySQL 一直都只有基于 statement 的复制模式,直到 5.1.5 版本的 MySQL 才开始支持 row 复制。从 5.0 开始,MySQL 的复制已经解决了大量老版本中出现的无法正确复制的问题。但是由于存储过程的出现,给 MySQL Replication 又带来了更大的新挑战。另外,看到官方文档说,从 5.1.8 版本开始,MySQL 提供了除 Statement 和 Row 之外的第三种复制模式:Mixed,实际上就是前两种模式的结合。在 Mixed 模式下,MySQL 会根据执行的每一条具体的 SQL 语句来区分对待记录的日志形式,也就是在 statement 和 row 之间选择一种。新版本中的 statment 还是和以前一样,仅仅记录执行的语句。而新版本的 MySQL 也对 row 模式做了优化,并不是所有的修改都会以 row 模式来记录,比如遇到表结构变更的时候就会以 statement 模式来记录,如果 SQL 语句确实就是 update 或者 delete 等修改数据的语句,那么还是会记录所有行的变更。

    生命周期

    事务提交的时候,一次性将事务中的 sql 语句(一个事务可能对应多个 sql 语句)按照一定的格式记录到 binlog 中,这里与 redo log 很明显的差异就是 redo log 并不一定是在事务提交的时候才刷新到磁盘,而是在事务开始之后就开始逐步写入磁盘。binlog 的默认保存时间是由参数 expire_logs_days 配置的,对于非活动的日志文件,在生成时间超过 expire_logs_days 配置的天数之后,会被自动删除。

    binlog和redo log 写入的细节 - 两阶段提交

    MySQL通过两阶段提交来保证redo log和binlog的数据是一致的

    update T set c=c+1 where ID=2;
    

    这里我给出这个 update 语句的执行流程图,图中浅色框表示是在 InnoDB 内部执行的,深色框表示是在执行器中执行的

    file

    将 redo log 的写入拆成了两个步骤:prepare 和 commit,这就是"两阶段提交"。

    附:

    image

     

    展开全文
  • 什么是redo log和undo log

    2021-12-03 13:52:15
    MySQL日志系统中最重要的日志为重做日志redo log和归档日志bin log,后者为MySQL Server层的日志,前者为InnoDB存储引擎层的日志。 1 重做日志redo log 1.1 什么是redo log redo log用于保证事务的持久性,即ACID...
  • redo log的数据结构之前我们已经对redo log的作用进行了初步的介绍,现在我们就要深入研究一下redo log的一些技术细节了。首先我们来看看写入磁盘上的日志文件的redo log大致长个什么样。redo log里本质上记录的就是...
  • 目录重做日志(redo log)重做日志-作用重做日志-内容重做日志-什么时候产生重做日志-什么时候释放重做日志-对应的物理文件重做日志-其他回滚日志(undo log)回滚日志-作用回滚日志-内容回滚日志-什么时候产生回滚日志-...
  • mysql日志模块binlog/redolog/undolog

    千次阅读 2021-01-27 18:56:24
    目录背景物理日志逻辑日志日志模块:redo logredo log产生背景redo log基本概念redo log记录形式redo log使用场景日志模块:bin logbin log基本概念bin log刷盘机制bin log使用场景日志模块:undo logundo log基本...
  • innodb事务日志包括redo log和undo logredo log是重做日志,提供前滚操作,undo log是回滚日志,提供回滚操作。undo log不是redo log的逆向过程,其实它们都算是用来恢复的日志:1.redo log通常是物理日志,记录的...
  • undolog称为回滚日志是mysql服务层的东西,而redolog和undolog是innodb引擎层的东西。 一、redoLog MySQL的数据最终是存放在磁盘中的,但是如果操作都是通过读写磁盘来进行的话,磁盘的I/O效率太低。所以InnoDB(又...
  • 二、回滚日志(undo log) 作用: 保存了事务发生之前的数据的一个版本,可以用于回滚,同时可以提供多版本并发控制下的读(MVCC),也即非锁定读 三、二进制日志(binlog): 作用: 用于复制,在主从复制中,...
  • innodb事务日志包括redo log和undo logredo log是重做日志,提供前滚操作,undo log是回滚日志,提供回滚操作。undo log不是redo log的逆向过程,其实它们都算是用来恢复的日志:1.redo log通常是物理日志,记录的...
  • ACID实现事务(Transaction)实现着重于实现事务的ACID属性,即:原子性(Atomic)一致性(Consistency)隔离性(Isolation)持久性(Duration)事务的隔离性由锁机制MVCC实现,原子性(Atomic)由Undo Log实现,持久性由Redo ...
  • 没错,这就是接下来我们要介绍的另外的两个关键功能,Redo Log和Undo Log。 这两种日志是属于InnoDB存储引擎的日志,MySQL Server的Binlog不是一个维度的日志。 Redo Log 记录了此次事务**「完成后」** 的数据状态...
  • InnoDB存储引擎引入RedoLog和UndoLog事务日志,用于提升事务场景下的数据库性能。本文会对RedoLog和UndoLog进行介绍。 RedoLog和UndoLog ChangeBufferWAL 我们以一条SQL更新语句来介绍RedoLog的作用,首先在数据库...
  • 分别是:重做日志(redo log)、回滚日志(undo log)、二进制日志(binlog)、错误日志(errorlog)、慢查询日志(slow query log)、一般查询日志(general log),中继日志(relay log)。 其中重做日志回滚...
  • 我们了解了一条查询语句的执行过程,按理说这篇应该讲一条更新语句的执行过程,但这个过程比较复杂,涉及到了好几个日志与事物,所以先梳理一下3个重要的日志,bin log(归档日志)、redo log(重做日志)、undo log(回滚日志...
  • Apple iPhone 11 (A2223) 128GB 黑色 移动联通电信4G手机 双卡双待4999元包邮去购买 >日志是mysql数据库的重要组成部分,...作为开发,我们重点需要关注的是二进制日志(binlog)事务日志(包括redo log和undo log...
  • 作为开发,我们重点需要关注的是二进制日志(binlog)事务日志(包括redo log和undo log),本文接下来会详细介绍这三种日志。binlogbinlog用于记录数据库执行的写入性操作(不包括查询)信息,以二进制的形式保存在磁盘...
  • redo log重做日志undo log撤消日志重做日志:每当有操作执行前,将数据真正更改时,先前相关操作写入重做日志。这样当断电,或者一些意外,导致后续任务无法完成时,系统恢复后,可以继续完成这些更改撤消日志:当...
  • 而Mysql日志又分为错误日志、查询日志、慢查询日志、二进制日志(binlog)事务日志(redo logundo log)。其中在我们开发中聊的比较多的就是二进制日志(binlog)事务日志(redo logundo log)。其实慢查询日志也是...
  • 磁盘速度越快就设置越大,建议磁盘IOPS一样 # innodb_flush_neighbors=0 #刷脏页时是否把数据页旁边的脏页也刷掉,1为一起刷,SSD磁盘建议为0,8.0开始默认为0 三、Undo log(事务回滚日志) 1、Undo log作用 Undo...
  • Undo Log,Redo Log和Binlog MySQL隔离级别,一致性视图,undo logredo log和binglog MySQL索引结构,回表,最左前缀原则 Mysql相关 1、innoDB跟myisam的区别; 2、InnoDB的索引实现,唯一索引、覆盖索引、前缀...
  • 事务一旦开启之后就开始产生redologredolog并不需要等待事务提交之后才写入磁盘,而是事务的执行过程中,便开始写入redolog文件,redolog是按照顺序写入redolog文件中的。 事务开启之后redolog的逐步写盘是如何...
  • 文章目录Mysql日志全解Mysql日志类型redo-log 重做日志作用内容什么时候产生什么时候落盘什么时候释放对应的物理文件参数配置脏页其他undo-log 回滚日志作用内容什么时候产生什么时候释放对应的物理文件其他 ...
  • 文章目录1、从MySQL的WAL说起2、再说说Crash-Safe3、三大核心日志模块4、两阶段提交5、组提交6、"双1"设置7、崩溃与数据恢复流程8、Bin log vs Redo log9、附录9.1、MySQL执行架构9.2、Redo log文件格式9.3、Binlog...
  • transaction:事务一个事务会在数据库中申请资源来完成任务,事务或复杂或简单,最后都只有两个结果,事务成功或者失败,成功需要保存事务更改,...redo log是为了重现已经做过的操作undo log:撤销日志为了保证读...
  • 一条查询语句的执行过程一般是经过连接器、分析器、优化器、执行器等功能模块,最后到达存储引擎。 那么,一条更新语句的执行流程又是怎样的呢...这里的日志是指重做日志,在InnoDB存储引擎中,由两部分组成,即redo log和

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 39,566
精华内容 15,826
关键字:

loglog和redoundo