当前位置:   article > 正文

MySQL:redo log buffer

redo log buffer

什么是redo log buffer

我们平时执行完增删改之后,要写入磁盘的redo log,其实应该是先进入redo log block这个数据结构里去的,然后在进入磁盘文件里:
在这里插入图片描述
也就是说redo log先通过内存缓存之后,再进入到磁盘文件里去的。这里涉及到了一个新的组件,redo log buffer,它是MySQL专门涉及用来缓存redo log写入的。

这个redo log buffer其实就是MySQL在启动的时候,跟操作系统申请的一块连续内存空间,和buffer pool(申请之后划分了N个空的缓存页和一些链表结构,让你把磁盘上的数据加载到内存里来)的作用类似,它申请之后划分了N个空的redo log block。redo log buffer结构如下图:

在这里插入图片描述
通过设置MySQL的innodb_log_buffer_size可以指定这个redo log buffer的大小,默认是16MB,其实已经够大了,因为一个redo log block才512字节而已,每一个redo log也不过几个字节到几十个字节罢了。

redo log都是先写入到内存里的redo log block数据结构里,然后block满了之后才会把redo log block写入到磁盘文件里去,而不是直接把redo log写入磁盘。

  • 当要写一条redo log的时候,会先从第一个redo log block开始写入,如下图:
    在这里插入图片描述
  • 写满了一个redo log block,就会继续写下一个redo log block,以此类推,直到所有的redo log block都写满。
  • 要是redo log buffer里所有的redo log block都写满了,就会强制把redo log block刷入磁盘中去。
  • redo log block刷入磁盘文件,本质就是把512字节的redo log block追加到redo log日志文件里去

如下图,表示在磁盘文件里不停的追加一个又一个的redo block:
在这里插入图片描述

在我们平时执行一个事务的过程中:

  • 每个事务会有多个增删改操作,那么就会有多个redo log,这多个redo log就是一组redo log。每次一组redo log都是先在别的地方暂存,然后都执行完了,再把一组redo log写入到redo log buffer的 block里去的。
  • 如果一组redo log实在是太多了,那么就可能会存放在两个redo log block中。如下图:
    在这里插入图片描述
  • 如果说一个redo log group比较小,那么也可能多个redo log group是在一个redo log block里的。如下图:
    在这里插入图片描述

redo log buffer中的缓冲日志,到底什么时候可以写入磁盘

redo log在写的时候,都是一组事务里的一组redo log,先暂存在一个地方,完事之后把一组redo log写入redo log buffer。

写入redo log buffer的时候,是写入里面提前划分好的一个一个的redo log block机制的,选择有空闲空间的redo log block去写入,等redo log block写满之后,会在某个时机刷入磁盘里去。

问题: redo log block是哪些时候会刷入到磁盘里去?

(1)如果写入redo log buffer的日志已经占据了redo log buffer总容量的一半了,也就是超过了8MB的redo log在缓冲里了,此时就会把它们刷入到磁盘里去。

  • 一个场景:如果你瞬间执行大量的高并发SQL语句,1s内就产生了超过8MB的redo log,此时占据了redo log buffer一半的空间了,必然会把redo log刷入磁盘。
    在这里插入图片描述
  • 这种redo log刷盘的情况,在MySQL承载高并发请求的时候比较场景。但是实际情况中很少遇到

(2)一个事务提交的时候,必须把它的那些redo log block都刷入到磁盘文件里去,只有这样,当事务提交之后,它修改的数据绝对不会丢失,因为redo log里有重做日志,随时可以恢复事务做的修改(注意redo log哪怕事务提交的时候写入磁盘文件,也是先进入 os cache的,进入 os的文件缓冲区里,所以是否提交事务就强行把 redo log刷入物理磁盘文件中,这个需要设置对应的参数)

  • 其实就是平时执行一个事务,这个事务一般都是在几十毫秒到几百毫秒执行完毕的,说实在的,一般正常性能情况下,MySQL单事务性能一般不会超过1秒,否则数据库操作就太慢了。
  • 那么如果在几十毫秒,或者几百毫秒的时候,执行完毕了一个事务,此时必然会立马把这个事务的redolog都刷入磁盘。如下图:
    在这里插入图片描述
  • 这种情况非常常见,往往redo log刷盘都是以一个短事务提交时候发生的。
  • 也就是说,必须保证一个事务执行的时候,redo log都进入redo log buffer,提交事务的时候,事务对应的redo log必须是刷入磁盘文件,接着才算事务提交成功,否则事务提交失败。保证这一点,就能确保事务提交之后,数据不会丢,有redo log在磁盘里就行了。
  • 当然,绝对保证数据不丢,还得配置一个参数,提交事务把redo log刷入磁盘文件的os cache之后,还需强行从os cach刷入物理磁盘。
  • mysql通过innodb_flush_log_at_trx_commit配置来控制redo log的写盘时机。
    • 0:延迟写。提交事务时不会将redo log写入os buffer,而是每隔1秒将redo log写入os buffer并调用fsync()刷入磁盘。系统崩溃会丢失一秒钟的数据。
    • 1:实时写,实时刷。每次提交事务都将redo log写入os buffer并调用fsync()刷入磁盘。这种方式系统奔溃不会丢失数据,因每次提交事务都写入磁盘,性能比较差(推荐)
    • 2:实时写,延时刷。每次提交事务都将redo log写入os buffer,但并不会马上调用fsync()刷如磁盘,而是间隔1秒调fsync()刷盘。相对于每次提交都写盘和每隔1秒写盘,实施写os buffer延时刷盘是一个数据一致性与性能的之间的这种方案。
  • 一般都是推荐设置为1,因为redo log的本身就是为了保证事务提交后数据不丢失的。而且其实redo log的写磁盘操作时顺序写入的,性能也是比较高的。

(3)后台线程定时刷新,有一个后台线程每隔1s就会把redo log buffer里的redo log block刷到磁盘文件里去。

(4)MySQL关闭的是,redo log block都会刷入到磁盘里去

问题:我们平时不停的执行增删改,那么MySQL会不停的产生大量的redo log写入日志文件,那么日志文件就用一个写入全部的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就可以了。

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

如果你还想保留更多的redo log,其实调节上述两个参数就可以了,比如每个redo log文件是96MB,最多保留100个redo log文件。下面图里,展示出来了多个redo log文件循环写入的示意。

在这里插入图片描述

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/你好赵伟/article/detail/575935
推荐阅读
相关标签
  

闽ICP备14008679号