目录

1. 引言

2. 重做日志文件和相关概念介绍

  +  2.1. 重做日志文件和bin log

  +  2.2. LSN(log squence number)

3. 重做日志文件基本工作原理

4. 重做日志文件物理结构

  +  4.1. 重做日志块文件

  +  4.2. 重做日志文件

5. 重做日志文件的恢复

6. 相关控制参数及其作用

1. 引言

在数据库中,事务有着四个特性,即A(actomicity)原子性、C(consistency)一致性、I(isolation)隔离性、D(Durable)持久性。在innodb中,对于这几个特性的innodb中有着不同的部分进行实现。例如A(actomicity)原子性、D(Durable)持久性采用重做日志文件的方式进行实现;C(consistency)一致性采用undo日志文件的方式进行实现;I(isolation)隔离性的要求,采用锁的方式进行实现。

本文将介绍innodb中对于重做日志文件(redo log)的实现方式。水平有限,如有错误欢迎指正。

2. 重做日志文件和相关概念介绍

2.1. 重做日志文件和bin log

  在innodb中,事务修改一个记录中的数据,首先需要保证记录所以在的页在内存当中,并在内存中修改之后,将修改后的数据持久化到磁盘当中。为了能够保证在事务在commit之后,数据还没有完全刷新到磁盘的情况下,修改的数据不会因为在系统发生掉电、崩溃等情况下的丢失,其采用了日志先行的方式(WAL),即在持久化修改过的数据到磁盘之前,先将修改信息的日志文件存入磁盘当中,当发生上述的极端情况时,即可采用日志文件对数据进行恢复。

  在mysql中存在着两种不同的日志,1、二进制日志文件(bin log);2、重做日志文件

  对于bin log 其是一种逻辑日志,其是数据mysql上层的日志文件。所记录的是事务在操作过程中的SQL语句。并且只在事务提交的时候,一次性的写入到日志当中。

  对于重做日志文件其是innodb在物理层面的日志。其记录的不是事务在执行过程中的SQL语句,而是记录的物理页面的修改情况。并且其在写入的时间点和bin log 是不同的。重做日志文件在事务执行的过程中,会被不断的写入。所以在物理层面上看来其事务的写入顺序不会是连续的。如图 2-1所示,在redo log 的日志写入顺序并不会是顺序的,且有可能不是连续的。(T2'、T3'、T1'代表了T1、T2、T3的剩余部分)

InnoDB存储引擎--学习笔记-redo log-LMLPHP

图 2-1 redo log 事务日志写入顺序示意图

2.2. LSN(log squence number)

  在innodb有一个重要的数据为LSN即log squence number的缩写。其大小为8个字节,是一个不断递增的整数。通过其,来记录当前修改的脏页的日志序列号、checkpoint、重做日志文件的序号等。

  在重做日志中,LSN表示了当前写入日志文件的总字节数,例如当前的LSN为2582,当有一个事务T1写入了258个字节时,则当前的LSN变为2582+258=2,840。在innodb中重做日志文件的LSN分为两个部分,1、缓存中的日志文件的LSN;2、磁盘中日志文件的LSN。

  在innodb的每个页的结构中,都存在着一个FIL_PAGE_LSN结构,用来标识改页在最后被刷新到磁盘的时候,当前的LSN的大小。通过这个结构,可以在数据库启动时,通过重做日志文件的LSN的值和页中FIL_PAGE_LSN进比较,如果发现FIL_PAGE_LSN的值小于重做日文件中的LSN,则需要进行恢复,反正,则表示页已经完全刷新到磁盘不需要恢复。

  上面的叙述中,有一个细节故意被忽略了,即对于没有提交的事务,其数据是否需要进行恢复。在innodb中,采取的策略是,每次启动系统,都尝试恢复数据库中的数据,对于没有commit的数据页采用相同的操作。之后再根据undo日志文件中的信息,对于未commit的数据进行回滚,从而保证了整个数据的一致性和持久性。

  在innodb中,master线程每隔一段时间都要进行刷新操作,即将内存中的脏页刷新到磁盘上。所以数据库中,页的刷新是异步的。所以每个一个时段刷新数据的方法,可以成为检查点技术即checkpoint。在innodb中checkpoint的值,也是采用的LSN进行的记录。例如使用命令:show innodb status;在mysql的命令行中,可以显示innodb的状态信息,翻找其中的“LOG”标识有如下的内容:

Log sequence number
Log flushed up to
Last checkpoint at

  1、Log sequence number:表示缓存中的日志文件的LSN的值

  2、Log flushed up to:表示刷新到日志文件的LSN的值

  3、Last checkpoint at :表示最后一次刷新的时候,LSN的值

3. 重做日志文件基本工作原理

Innodb中重做日志文件主要有以下的几个部分组成:

  • 重做日志缓存(redo log buffer)
  • 重做日志文件组(redo log group)
  • 重做日志文件(redo log file)

  其之间的关系,可以使用图 3-1表示。可以整理得到如下的几个信息:

  1、如图所示,redo log buffer位于内存之中,重做日志文件组和重做日志文件位于磁盘至上。(PS一般而言,innodb只提供了一个重做日志文件组的选择。因为在其源码中默认选择了不启动日志文件的镜像功能。)

InnoDB存储引擎--学习笔记-redo log-LMLPHP

图 3-1

  2、重做日志文件组由重做日志文件组成,在一个组内可以有多个重做日志文件。在磁盘上重做日志文件ib_logfile[number]命名,在磁盘mysql的安装目录data文件夹下,可以看到如下的两个文件,即为redo log file。

InnoDB存储引擎--学习笔记-redo log-LMLPHP

图 3-2

  3、在图 3-1中可以看出,日志文件缓存先由内存中写到日志上是以512字节的方式进行写入的。同时写redo log file的方式也是采用重复循环写的方式,即先写logfile1,如果logfile1写满了之后再写logfile2,之后logfile2写满再写logfile3。如果logfile3写满了,再重新写logfile1。在innodb内部,redo log files 是被当做一个逻辑整体进行看待的,对应着同一个space id。如前所述,每次日志文件是采用512字节的方式进行写入的,所以可以很方便的根据全局维护的LSN计算出当前写入到哪一个文件以及对应的偏移量。

4. 重做日志文件物理结构

4.1. 重做日志块文件

  如上文所述,重做日志文件缓存从内存中写入磁盘是采用每次写512字节的方式写入,因为每次写入512字节大小的数据和磁盘的扇区大小是一致的,所以操作是原子性,不需要采用doublewrite的方式。

  每次写入的512字节,在系统中以一定的结构进行表示,称之为重做日文件块(redo log block)。重做日文件块构成了重做日志缓存的基础。

重做日志文件缓存会根据一定的规则刷新到重做日志文件当中:

  1、事务commit时

  2、写入检查点

  3、Log buffer 中日志文件信息超过一定的阈值之后

  redo log block结构如图 4-1所示:

InnoDB存储引擎--学习笔记-redo log-LMLPHP

图 4-1

  在图中我们可以看到redo log block 主要由以下的三个部分构成

  1、日志文件块头:其占12 byets 由4个部分构成

  2、日志文件块本体:占有492 byets

  3、日志文件块尾:占有8 bytes

  一个事务数据在block中的分布可以由图 4-2进行描述,如图所示,T1的事务数据大于419个字节,所以被分配在了两个block中。并在第二个block中占有了100个字节。之后才是T2的事务数据开始。为了能够标识一个block中,一个完整的事务信息开始的位置,日志文件块头中的LOG_BLOCK_FIRST_REC_GROUP,被用来作为标识。当前这个例子中LOG_BLOCK_FIRST_REC_GROUP的值应该为12+100=112。(12为头信息长度,100为T1在第二个事务块中的字节大小)

InnoDB存储引擎--学习笔记-redo log-LMLPHP

图 4-2

4.2. 重做日志文件

  重做日志文件为重做日志文件缓存在磁盘上的持久化提供支持。假设当前重做日志文件组中存在着两个重做日志文件,logfile1和logfile2。其日志文件结构如图 4-3所示。如前文所述,在重做日志文件组中对于日志文件不管有多少个都是按照一个文件来进行看待的。从图中可以看出第一个日志文件中保存了4个512字节大小的头部,共2KB,而在第二个日志文件中前2KB的空间被放空。

InnoDB存储引擎--学习笔记-redo log-LMLPHP

图 4-3

  对于前2KB的信息,主要由以下的几个部分组成:

  1、Log file header

  这个部分主要记录了以下的几个部分的信息如图 4-4所示:

InnoDB存储引擎--学习笔记-redo log-LMLPHP

图 4-4

  LOG_GROUP_ID :用于记录日志文件组的ID

  LOG_FRIST_START_LSN:用于记录重做日志文件第一个块的LSN号

  2、CP1和CP2

  为了避免在写入介质的时候失败,日志文件组中的第一个日志文件总共保存了两个检查点的信息,即CP1和CP2(CP1和CP2中的结构不加以展开说明)。

5. 重做日志文件的恢复

  前文中提到过,不管系统启动的时候,之前有没有发生过异常的情况,系统都会尝试去执行重做操作。在innodb中对于重做的操作,主要有以下的几个步骤构成:

  1、判断是否需要进行重做

  在innodb中表空间中的(0,0)页是一个比较特殊的页,仅在页的头部定义了LSN的值。该部分记录了数据库系统正常关闭的时候,最后刷新的页的LSN的值,倘若系统正常关闭则此值应该和checkpoint的值相同。因此首先通过此值对于系统是否正常启动进行判断

  2、获取最近检查点

  如上文所述,在日志文件组中的第一个文件中,保存了两个CP值。通过对其进行分析找出最大检查点值

  3、分析日志文件并重做

  根据步骤3获得的checkpoint信息,分析重做日志文件,根据其内容中的space 和 offet ,放进不同的哈希表slot中。对于页中LSN的值大于checkpoint的便跳过重做。

6. 相关控制参数及其作用

  1、innodb_flush_log_at_trx_commit

  这个参数用来控制重做日志文件的磁盘刷新策略。当值为0时,日志缓冲每秒一次地被写到日志文件,并且对日志文件做到磁盘操作的刷新,但是在一个事务提交不做任何操作。当值为1时,在每个事务提交时,日志缓冲被写到日志文件,对日志文件做到磁盘操作的刷新。当值为2时,在每个提交,日志缓冲被写到文件,但不对日志文件做到磁盘操作的刷新。对日志文件每秒刷新一次。

  2、Innodb_log_buffer_size

  这个参数用来控制重做日志文件缓存的大小默认为1MB。Log Buffer的主要作用就是缓冲Log数据,提高写Log的IO性能。

  3、Innodb_log_group_home_dir

  这个参数用来控制重做日志文件所在的路径

  4、Innodb_log_files_in_group

  这个参数用来控制重做日志文件组中日志文件的个数

  5、Innodb_log_file_size

  这个参数用来控制重做日志文件组中,每个文件的大小。默认是5MB。所有的重做日志文件加起来大小不可以超过4GB

05-11 22:23