MySQL性能优化(四)redo log实现原理

x33g5p2x  于2022-05-18 转载在 Mysql  
字(3.2k)|赞(0)|评价(0)|浏览(337)

1.redo log的作用

首先我们都知道,执行增删改SQL语句的时候,都是针对一个表中的某些数据去执行的,此时的话,首先必须找到这个表对应的表空间,然后找到表空间对应的磁盘文件,接着从磁盘文件里把你要更新的那批数据所在的数据页从磁盘读取出来,放到Buffer Pool的缓存页里去。

redo log可以保证我们事务提交之后,如果事务中的增删改SQL语句更新的缓存页还没刷到磁盘上去,此时MySQL宕机了,那么MySQL重启过后,就可以把redo log重做一遍,恢复出来事务当时更新的缓存页,然后再把缓存页刷到磁盘就可以了。

redo log本质是保证事务提交之后,修改的数据绝对不会丢失的

那么有人会问了,你事务提交的时候把修改过的缓存页都刷入磁盘,跟你事务提交的时候把你做的修改的redo log都写入日志文件,他们不都是写磁盘么?差别在哪里?

实际上,如果你把修改过的缓存页都刷入磁盘,这首先缓存页一个就是16kb,数据比较大,刷入磁盘比较耗时,而且你可能就修改了缓存页里的几个字节的数据,难道也把完整的缓存页刷入磁盘吗?而且你缓存页刷入磁盘是随机写磁盘,性能是很差的,因为他一个缓存页对应的位置可能在磁盘文件的一个随机位置,比如偏移量为45336这个地方。

但是如果是写redo log,第一个一行redo log可能就占据几十个字节,就包含表空间好、数据页号、磁盘文件偏移量、更新值,这个写入磁盘速度很快。此外,redo log写日志,是顺序写入磁盘文件,每次都是追加到磁盘文件末尾去,速度也是很快的。所以你提交事务的时候,用redo log的形式记录下来你做的修改,性能会远远超过刷缓存页的方式,这也可以让你的数据库的并发能力更强。

2.redo log的结构

2.1.redo log 记录

redo log里本质上记录的就是在对某个表空间的某个数据页的某个偏移量的地方修改了几个字节的值,具体修改的值是什么,他里面需要记录的就是:
日志类型,表空间ID,数据页号,数据页中的偏移量,具体修改的数据

一条redo log中依次排列上述的一些东西,这条redo log表达的语义就很明确了,他的类型是什么,类型就告诉了你他这次增删改操作修改了多少字节的数据;然后在哪个表空间里操作的,这个就是跟你SQL在哪个表里执行的是对应的;接着就是在这个表空间的哪个数据页里执行的,在数据页的哪个偏移量开始执行的,具体更新的数据是哪些呢。有了上述信息,就可以精准完美的还原出来一次数据增删改操作做的变动了。

2.2.redo log block

我们已经知道了redo log的记录样子,我们可以想一下,redo log就是按照上述格式,一条一条的直接就写入到磁盘上的日志文件里去了吗?

其实MySQL内有另外一个数据结构,叫做redo log block,大概你可以理解为,平时我们的数据不是存放在数据页了的么,用一页一页的数据页来存放数据。那么对于redo log也不是单行单行的写入日志文件的,他是用一个redo log block来存放多个单行日志的。

一个redo log block是512字节,这个redo log block的512字节分为3个部分,一个是12字节的header块头,一个是496字节的body块体,一个是4字节的trailer块尾。在这里面,12字节的header头又分为了4个部分。

要写入磁盘的redo log,其实应该是先进入到redo log block这个数据结构里去的,然后再进入到磁盘文件里,如下图所示。

redo log数据——》redo log block——》redo log文件

2.3.redo log buffer

redo log到底是如何通过内存缓冲之后,再进入磁盘文件里去的,这就涉及到了一个新的组件,redo log buffer,他就是MySQL专门设计了用来缓冲redo log写入的。

redo log buffer其实就是MySQL在启动的时候,就跟操作系统申请的一块连续内存空间,然后里面划分出了N多个空的redo log block。mysql的innodb_log_buffer_size可以指定这个redo log buffer的大小,默认的值就是16MB,其实已经够大了,毕竟一个redo log block才512字节而已,每一条redo log其实也就几个字节到几十个字节罢了

redo log都是先写入内存里的redo log block数据结构里去的,写满了一个redo log block,就会继续写下一个redo log block,以此类推,直到所有的redo log block都写满。然后完事儿了才会把redo log block写入到磁盘文件里去的。

万一要是redo log buffer里所有的redo log block都写满了呢?
那此时必然会强制把redo log block刷入到磁盘中去的!

其实在我们平时执行一个事务的过程中,每个事务会有多个增删改操作,那么就会有多个redo log,这多个redo log就是一组redo log,其实每次一组redo log都是先在别的地方暂存,然后都执行完了,再把一组redo log给写入到redo log buffer的block里去的。

3.redo log buffer 刷盘

redo log block在什么时候会刷入到磁盘文件里去:

  1. 如果写入redo log buffer的日志已经占据了redo log buffer总容量的一半了,也就是超过了8MB 的redo log block在缓冲里了,此时就会把他们刷入到磁盘文件里去;
  2. 一个事务提交的时候,必须把他的那些redo log所在的redo log block都刷入到磁盘文件里去,只有这样,当事务提交之后,他修改的数据绝对不会丢失,因为redo log里有重做日志,随时可以恢复事务做的修改
  3. 后台线程定时刷新,有一个后台线程每隔1秒就会把redo log buffer里的redo log block刷到磁盘文件里去
  4. MySQL关闭的时候,redo log block都会刷入到磁盘里去

当然,绝对保证数据不丢,还得配置一个参数,提交事务把redo log刷入磁盘文件的os cache之后,还
得强行从os cache刷入物理磁盘。

最后给大家说一下redo log日志文件的问题,我们都知道平时不停的执行增删改,那么MySQL会不停的
产生大量的redo log block写入日志文件,那么日志文件就用一个写入全部的redo log?对磁盘占用空间越来越大怎么办?

实际上默认情况下,redo log都会写入一个目录中的文件里,这个目录可以通过show variables like 'datadir’来查看,可以通过innodb_log_group_home_dir参数来设置这个目录的。

然后redo log是有多个的,写满了一个就会写下一个redo log,而且可以限制redo log文件的数量,通
innodb_log_file_size可以指定每个redo log文件的大小,默认是48MB,通过innodb_log_files_in_group可以指定日志文件的数量,默认就2个。

所以默认情况下,目录里就两个日志文件,分别为ib_logfile0和ib_logfile1,每个48MB,最多就这2个
日志文件,就是先写第一个,写满了写第二个。那么如果第二个也写满了呢?别担心,继续写第一个,
覆盖第一个日志文件里原来的redo log就可以了。

所以最多这个redo log,mysql就给你保留了最近的96MB的redo log而已,不过这其实已经很多了,毕
竟redo log真的很小,一条通常就几个字节到几十个字节不等,96MB足够你存储上百万条redo log
了!

如果你还想保留更多的redo log,其实调节上述两个参数就可以了,比如每个redo log文件是96MB,
最多保留100个redo log文件

相关文章

微信公众号

最新文章

更多