MySQL崩溃恢复功臣—Redo Log

不同于binlog是MySQL Server层的日志,Redo log是InnoDB引擎特有的日志。Redo log文件是InnoDB用于崩溃恢复(crash recovery)以及组提交(group commit)策略的重要文件,存在于磁盘上。下面大致讲解下Redo log是怎么做到崩溃恢复以及组提交的。

崩溃恢复

崩溃恢复能力是指InnoDB可以保证数据库在异常崩溃重启后的状态和使用binlog文件恢复出来的数据库状态保持一致。

如果没有redo log

我们可以假设没有redo log,只有binlog,那么数据文件更新和写入binlog的顺序有两种可能:

  • 第一种
    1. 更新数据文件
    2. 写入binlog
  • 第二种
    1. 写入binlog
    2. 更新数据文件

第一种情况如果在完成步骤1后服务器异常关闭,则导致binlog中缺少最后更新的数据;第二种情况如果在完成步骤1后服务器异常关闭,则数据库中比binlog中少了最后的数据变更记录。此时如果使用binlog文件进行恢复数据库(比如备库),则会导致数据库不一致的情况。

redo log是怎么做的

先上一张图,是InnoDB更新数据时update语句的执行流程(摘自极客时间《MySQL实战45讲》,自己重新绘制),橙色的流程在InnoDB内部执行,蓝色的部分在MySQL Server层的执行器中执行。图片以下条sql语句为例。

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

如上图所示,redo log的写入分为两个阶段(prepare和commit),这个称作两阶段提交,保证了数据的正确性。下面我们从上图4个可能发生异常关闭的时间点来分析InnoDB如何在MySQL启动时做崩溃恢复。

Point A

如果服务器异常关闭发生在Point A以及之前的时间点,这个时候redolog 和 binlog都没有任何记录,事务还未提交,不会造成任何影响。

Point B

当服务器启动的时候发现redo log里处于prepare状态的记录,这个时候需要检查binlog是否完整包含此条redo log的更新内容(通过全局事务ID对应),发现binlog中还未包含此事务变更,则丢弃此次变更。

Point C

和Point B基本相同,只不过此时发现binlog中包含redo log的更新内容,此时事务会进行提交。

Point D

binlog中和数据库中均含有此事务的变更,没有任何影响。

组提交

上面关于崩溃恢复部分只是讲了写redo log和binlog的步骤,那么一定很疑惑数据是何时被写入到磁盘文件中的呢,这里就要说下InnoDB通过redo log实现的组提交的策略了。

因为更新数据时写磁盘的操作是随机写,这部分的IO消耗很大,而通过组提交(多个事务的变更统一写磁盘)的方式可以提升系统的吞吐量。

磁盘文件

默认是两个文件,存在datadir目录中,文件名分别为ib_logfile0ib_logfile1。datadir可以通过命令select @@datadir;查看:

mysql> select @@datadir;
+---------------------------------------+
| @@datadir                             |
+---------------------------------------+
| c:\wamp64\bin\mysql\mysql5.7.21\data\ |
+---------------------------------------+

文件数量和每个文件的大小可以通过变量innodb_log_files_in_groupinnodb_log_file_size来设置,这两个变量都是只读变量,只能通过在配置文件中修改并重启的方式生效。redo log文件的总大小(innodb_log_file_size * innodb_log_files_in_group)一般建议配置为可以处理一个小时写操作的量,数值越大则通过checkpoint刷新的次数越少,就越能降低磁盘IO。

配置文件(my.cnf/my.ini):

[mysqld]
innodb_log_files_in_group=4
innodb_log_file_size=1073741824

查看变量:

mysql> show variables like 'innodb_log_file%';
+---------------------------+------------+
| Variable_name             | Value      |
+---------------------------+------------+
| innodb_log_file_size      | 1073741824 |
| innodb_log_files_in_group | 4          |
+---------------------------+------------+

查看磁盘文件:

C:\wamp64\bin\mysql\mysql5.7.21\data
λ ls -alh | grep ib_log
-rw-r--r-- 1 username 1049089 1.0G Apr 24 10:45 ib_logfile0
-rw-r--r-- 1 username 1049089 1.0G Apr 24 10:44 ib_logfile1
-rw-r--r-- 1 username 1049089 1.0G Apr 24 10:44 ib_logfile2
-rw-r--r-- 1 username 1049089 1.0G Apr 24 10:45 ib_logfile3

组提交实现

如下图是一组redo log文件的工作的示意图(摘自极客时间《MySQL实战45讲》,自己重新绘制)

redo_log_ring

如图中所示,一组redo log文件是一个类似环形的状态,循环利用。

write pos指的是当前写入redo log的位置,check point是要擦除并更新到数据文件的位置,所以write pos 到check point 位置就是还未使用的空闲空间。

何时会擦除redo log并更新到数据文件中

  1. 系统空闲时
  2. redo log文件没有空闲空间时,即write pos追上check point的时候
  3. MySQL Server正常关闭时

redo log和binlog的区别

  1. redo log是InnoDB引擎特有的;binlog是MySQL的Server层实现的,所有引擎都可以使用。
  2. redo log是物理日志,记录的是“在某个数据页上做了什么修改”;binlog是逻辑日志,记录的是这个语句的原始逻辑,比如“给ID=2这一行的c字段加1 ”。
  3. redo log是循环写的,空间固定会用完;binlog是可以追加写入的。“追加写”是指binlog文件写到一定大小后会切换到下一个,并不会覆盖以前的日志。

推荐

感兴趣的推荐订阅丁奇大神的专栏《MySQL实战45讲》,感觉是最负责的一个专栏作者,好多篇作者回复评论都有上百条,真心推荐超值,可以扫下图中二维码订阅。

MySQL实战45讲

原创声明,本文系作者授权云+社区发表,未经许可,不得转载。

如有侵权,请联系 yunjia_community@tencent.com 删除。

编辑于

我来说两句

0 条评论
登录 后参与评论

扫码关注云+社区