第21章 说过的话就一定要办到-redo日志(下)
redo日志文件#
redo日志刷盘时机#
我们前面说mtr运行过程中产生的一组redo日志在mtr结束时会被复制到log buffer中,可是这些日志总在内存里呆着也不是个办法,在一些情况下它们会被刷新到磁盘里,比如:
log buffer空间不足时
log buffer的大小是有限的(通过系统变量innodb_log_buffer_size指定),如果不停的往这个有限大小的log buffer里塞入日志,很快它就会被填满。设计InnoDB的大佬认为如果当前写入log buffer的redo日志量已经占满了log buffer总容量的大约一半左右,就需要把这些日志刷新到磁盘上。
事务提交时
我们前面说过之所以使用redo日志主要是因为它占用的空间少,还是顺序写,在事务提交时可以不把修改过的Buffer Pool页面刷新到磁盘,但是为了保证持久性,必须要把修改这些页面对应的redo日志刷新到磁盘。
后台线程不停的刷刷刷
后台有一个线程,大约每秒都会刷新一次log buffer中的redo日志到磁盘。
正常关闭服务器时
- 做所谓的
checkpoint时(我们现在没介绍过checkpoint的概念,稍后会仔细介绍,稍安勿躁) - 其他的一些情况…
redo日志文件组#
MySQL的数据目录(使用SHOW VARIABLES LIKE 'datadir'查看)下默认有两个名为ib_logfile0和ib_logfile1的文件,log buffer中的日志默认情况下就是刷新到这两个磁盘文件中。如果我们对默认的redo日志文件不满意,可以通过下面几个启动参数来调节:
innodb_log_group_home_dir
该参数指定了redo日志文件所在的目录,默认值就是当前的数据目录。
innodb_log_file_size
该参数指定了每个redo日志文件的大小,在MySQL 5.7.21这个版本中的默认值为48MB,
innodb_log_files_in_group
该参数指定redo日志文件的个数,默认值为2,最大值为100。
从上面的描述中可以看到,磁盘上的redo日志文件不只一个,而是以一个日志文件组的形式出现的。这些文件以ib_logfile[数字](数字可以是0、1、2…)的形式进行命名。在将redo日志写入日志文件组时,是从ib_logfile0开始写,如果ib_logfile0写满了,就接着ib_logfile1写,同理,ib_logfile1写满了就去写ib_logfile2,依此类推。如果写到最后一个文件该咋办?那就重新转到ib_logfile0继续写,所以整个过程如下图所示:

总共的redo日志文件大小其实就是:innodb_log_file_size × innodb_log_files_in_group。 小贴士:如果采用循环使用的方式向redo日志文件组里写数据的话,那岂不是要追尾,也就是后写入的redo日志覆盖掉前面写的redo日志?当然可能了!所以设计InnoDB的大佬提出了checkpoint的概念,稍后我们重点介绍~
redo日志文件格式#
我们前面说过log buffer本质上是一片连续的内存空间,被划分成了若干个512字节大小的block。将log buffer中的redo日志刷新到磁盘的本质就是把block的镜像写入日志文件中,所以redo日志文件其实也是由若干个512字节大小的block组成。
redo日志文件组中的每个文件大小都一样,格式也一样,都是由两部分组成:
- 前2048个字节,也就是前4个block是用来存储一些管理信息的。
- 从第2048字节往后是用来存储
log buffer中的block镜像的。
所以我们前面所说的循环使用redo日志文件,其实是从每个日志文件的第2048个字节开始算,画个示意图就是这样:

普通block的格式我们在介绍log buffer的时候都说过了,就是log block header、log block body、log block trialer这三个部分,就不重复介绍了。这里需要介绍一下每个redo日志文件前2048个字节,也就是前4个特殊block的格式都是干嘛的,废话少说,先看图:

从图中可以看出来,这4个block分别是:


