InnoDB redo

一、REDO简介

  • redo log用于记录除了 SELECT的所有操作。
  • 重做日志作用是:当崩溃恢复期间用于前滚已经提交的数据,回滚未提交的数据。
  • MySQL以循环方式写入重做日志文件。
  • 重做日志的增加以LSN值表示。
  • 切换redo log的时候发生checkpoint,触发脏页的刷新
  • 默认情况下,innodb会创建2组大小均为5M的REDOLOG,分别为ib_logfile0、ib_logfile1,保存在datadir指定的路径下。相关的参数有下列几个
    • innodb_log_group_home_dir:指定redolog保存路径,默认在datadir指定的路径下
    • innodb_log_file_size:指定日志文件的大小,默认是5M,最大512G.该参数会影响检查点的执行频率,以及故障的恢复时间。一般来说,日志设置的越大,检查点执行的频率就越低,但是如果在这期间发生故障,启动的时候就会越长。
    • innodb_log_files_in_group:指定日志文件组的数量
    • innodb_fast_shutdown
      • 0:等到会话结束,事务结束,缓冲区的数据刷新到磁盘,类似shutdown normal
      • 1:关闭会话终止连接,将已提交的刷新到数据文件,未提交的回滚。类似shutdown immediate
      • 2:忽略所有操作,直接关闭数据,类似shutdown abort

     以上参数不支持动态修改

  • 触发 log buffer 刷新到 redo log的条件
    • commit,innodb_flush_log_at_trx_commit参数控制
      • 0:每秒刷新
      • 1:commit 的时候刷新到磁盘
      • 2:commit时刷新到系统的buffer中
    • redo log thread:1s,可以通过 innodb_flush_log_at_timeout 参数控制
    • redo log buffer:1/2

二、redo log 跟 binlog

2.1 redo log 跟 binlog的区别

第一:记录的内容不同

binlog记录数据的改变信息

redo log记录的是页的改变信息

 

第二:记录的时间不同

binlog记录commit后的操作

redolog记录事务发起后的操作

 

第三:文件使用方式不同

binlog写完会生成新的文件

redolog最后一个文件写完,会覆盖第一个文件

 

第四:作用不同

binlog可以作为恢复数据,主从搭建

redolog作为异常宕机后 Innodb实例会崩溃恢复

 

2.2 redo log 跟 binlog的关系

MySQL两阶段提交过程:

  • 准备过程:InnoDB 层写 prepare log
    • 写的还是 redo file
    • 写入的是 xid (事物 id)
  • 提交过程:分为2个步骤
    • 将binlog cache 中的事务写入 binlog 文件
    • 再在redo log中做一个事务提交的标记,并把 binlog 写成功的标记页一并写到 redo log文件中

 

场景一

准备阶段,redo log刷新到磁盘,但是binlog写盘前发生了MySQL实例crash。这时,即使redo log写盘成功了,但由于binlog未写入成功,也是需要回滚

场景二

提交阶段,binlog写盘成功了,这时候MySQL实例crash。这是binlog已经确保写成功了,重启MySQL的时候,检测到redo中和binlog中都有xid。那么,只需要让redo 强制提交就可以了

 

三、组提交

组提交主要是为了解决写日志时频繁刷磁盘的问题。

5.5 时只支持 redo 组提交,5.6之后支持 binlog 组提交,5.6之后的大并发性能问题比5.5好的一个原因

3.1 redo 组提交

事务提交时会进行两个阶段的操作:

  1. 将日志写入 redo log buffer
  2. 从 redo log buffer 写入磁盘

在没有 redo 组提交之前,步骤 2 相对于 步骤 1 的速度是较慢的。

出现 redo 组提交之后,多个事物 redo log 刷盘动作合并,减少 IO 调用。它的原理是:

redo log 中的 LSN 是单调递增的,每个事务的产生,都会获取到最大的 LSN。假设事务 trx1,trx2,trx3 对应的 LSN 分别是 LSN1,LSN2,LSN3,如果 trx3 先获取到 log_mutex 进行落盘,他就顺便可以把 LSN1,LSN2,LSN3 这段日志也进行刷盘。

但是,redo 组提交也只限于没有开启 binlog 的情况下,当开启了 binlog 之后,为了保证 redo 和 binlog的写入一致性。就涉及到一个两阶段提交:

prepare 阶段,innodb刷新 redo log,并将 UNDO 设置为 prepare 状态

commit 阶段,binlog 刷盘,最后设置 commit 状态。

对于多个事务的组提交,一个关键是保证事务在redo log和binlog中的顺序一致。上述的2PC并不能保证这一点。所以在 5.5 的时候就引入了 prepare_commit_mutex,见下图

prepare 阶段,持有 prepare_commit_mutex, innodb刷新 redo log,并将 UNDO 设置为 prepare 状态

commit 阶段,binlog 刷盘,最后设置 commit 状态。释放 prepare_commit_mutex。

持有 prepare_commit_mutex 期间,其他事务不能写 redo。这样就保证了串行执行。同时组提交失效,在 5.6 之后,为了解决这个问题,引入了 binlog group commit

 

3.2 binlog 组提交

binlog 组提交 引入了队列机制保证 innodb commit 顺序与 binlog 落盘顺序一致,并将事务分组,组内的 binlog 刷盘动作交给一个事务进行。binlog 组提交将提交分为了3个阶段

  1. FLUSH 阶段
    1. 持有 lock_log mutex (leader 持有,followr 等待)
    2. 获取队列中的一组 binlog (队列中的所有事务)
    3. 将 binlog buffer 到 I/O cache
    4. 通知 dump 线程 dump binlog
  1. SYNC 阶段
    1. 释放lock_log mutex,持有 lock_sync mutex(leader 持有,follower 等待)
    2. 将一组 binlog落盘(sync 动作,假设 sync_binlog 为1)
  1. COMMIT阶段
    1. 释放 lock_sync mutex,持有 lock_commit mutiex(leader持有,follower等待)
    2. 遍历队列中的事务,逐一进行 innodb commit
    3. 释放 lock_commit mutex
    4. 唤醒队列中等待的线程

 

3.3 组提交相关参数

binlog_group_commit_sync_no_delay_count:等待一组里面有多少事物我才提交

binlog_group_commit_sync_delay:等待多少时间后才进行组提交

 

参考书籍:《MySQL技术内幕》、《MySQL王者晋级之路》

参考博客:https://www.cnblogs.com/cchust/p/4439107.html

原文地址:https://www.cnblogs.com/ziroro/p/9833649.html