阅读 88

redo日志保证事务提交后数据绝对不会丢的机制

Buffer Pool整体机制

在MySQL进行更新操作的时候会先更新Buffer Pool中的缓存页之后,必须写一条redo log,这样才能记录下对数据库的修改,这样的话也可以保证我们事务提交之后,如果Buffer Pool中脏页还没有刷到磁盘上去时,MySQL发生宕机,那么MySQL重启后,就可以把redo log重做一遍,恢复出当时事务事务更新的缓存页,然后再把缓存页刷到磁盘,这样的话redo log就保证事务提交之后,修改的数据绝对不会丢。 在前面已经写过Buffer Pool查询的流程,大体如下面的图:

image.png

这里大家一个疑问:为什么在更新的时候不直接将数据写回磁盘,等磁盘数据更新完成后,事务才真正的成功呢?redo log也是写磁盘,这样岂不是多此一举呢? MySQL没有直接更新磁盘文件,主要是跟更新磁盘文件的性能相关,因为缓存页刷新到磁盘文件里,是随机磁盘读写,性能比较差,而且每个缓存页有16KB,写入的磁盘量也比较大,那么就会导致数据库性能和并发能力很弱,所以这才引入了redo log机制,在提交事务的时候,先绝对保证对缓存里的缓存页修改以日志记录的形式写入到redo log文件里才认为事务成功,因为写redo log 是依次在文件后面追加,顺序写磁盘的速度就跟写内存的效率相差不了多少,这样的话技能保证数据不丢,又能保证数据库的处理能力。

redo log日志格式

redo log本质记录的事对某个表空间的某个数据页的某个偏移量的地方修改了几个字节的值,具体修改的值是什么,需要记录的就是:**表空间+数据页号+偏移量+修改几个字节的值+具体的值,**根据修改数据页里的几个值,redo log划分了不同的类型:

  • MLOG_1BYTE类型:指的是修改了1个字节的值

  • MLOG_2BYTE类型:指的是修改了2个字节的值

  • 以此类推,还有修改了4个字节的值的日志类型,修改了8个字节的值的日志类型

  • 如果要是一下子修改了一大串的值,类型就是MLOG_WRITE_STRING,针对这种日志类型,需要知道具体修改了多少字节的数据,所以就会多一个修改数据长度

这时候日志格式大体为:

日志类型(类似MLOG_1BYTE) 表空间ID 数据页号 数据页中的偏移量 修改数据长度 具体修改的数据 复制代码

redo log block

redo log 在实际写入的时候并不是一条条的直接将日志写入到磁盘的日志文件里去,内部有一个redo log block数据结构,用redo log block 来存放多个单行日志。 一个redo log block是512字节,分为3部分:12字节header块头,496字节body块体,4字节trailer块尾

image.png

12字节的header头又分为4部分:

  • 4个字节block no:块唯一编号

  • 2个字节data length:block里写入了多少字节数据

  • 2个字节first record group:每个事务都会有多个redo log,是一个redo log group,即一组redo log。那么在这个block里的第一组redo log的偏移量,就是这2个字节存储的;

  • 4个字节checkpoint on

对于redo log,在写入的时候确实是不停的追加到redo log磁盘文件,但是其实是每个redo log都是写入文件里的一个redo log block里去的,一个block最多存放496字节的redo log日志。

image.png

redo log buffer

在写入磁盘的redo log,其实应该是先进入redo log block中去,然后在进入磁盘文件里,在MySQL启动的时候会跟操作系统申请一块连续内存空间,然后里面划分出了N个空的redo log block,如下图所示:

image.png

设置mysql的innodb_log_buffer_size可以指定redo log buffer大小,默认值是16MB,这个值相对比较大,因为一个redo log block才512KB,每一条redo log也就几个字节到几十个字节。redo log都是先写入内存里的redo log block数据结构里去的,然后完事后才会把redo log block写入到磁盘文件里。 当要写一条redo log的时候,就会先从第一个redo log block开始,写满一个redo log block,就会继续写下一个redo log block,以此类推,直到所有的redo log block都写满。

redo log buffer缓存日志刷盘时机

redo log写的时候,都是把一个事务里的一组redo log,先暂存在一个地方,当事务提交后把一组redo log写入redo log buffer,写入buffer的时候,是写入里面提前规划好的一个个redo log block,选择有空闲空间的block去写入,然后block写满之后,在刷入到磁盘里去。有下面几种情况会将block刷入磁盘文件里:

  1. 如果写入redo log buffer日志已经占据redo log buffer总容量的一半(默认8MB),此时就会刷入到磁盘文件里去

  2. 一个事务提交的时候,必须把他的那些redo log所在的redo log block都刷入到磁盘文件里去,只有这样,当事务提交之后,修改的数据绝对不会丢失

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

  4. MySQL关闭的时候,redo log block都会刷入到磁盘里去

这样可以保证一个事务执行的时候,redo log都进入redo log buffert,提交事务的时候吗,事务对应的redo log必须是刷入磁盘文件,接着才算是事务提交成功,否则是否就是失败,但是当把redo log刷入磁盘的时候,磁盘文件也有个os cache,这个时候就得配置redo log的刷盘策略,具体有三种策略:0,1,2

image.png

redo log文件

在运行期间会不停的执行增删改操作, 那么就会不停的写入日志文件,那么日志文件就会对磁盘占用空间越来越大,其实在写入的时候,redo log会写入一个目录中的文件里,可以通过innodb_log_group_home_dir参数来设置这个目录。然后redo log有多个,写满了一个就会写下一个,而且可以限制redo log文件的数量,通过innodb_log_fifile_size可以指定每个redo log文件的大小,默认是48MB,通过innodb_log_files_in_group可以指定日志文件数量,默认是2个。 默认情况下两个日志文件:ib_logfile0、ib_logfile1这两个文件循环写


作者:silly8543
链接:https://juejin.cn/post/7028375249259331592

文章分类
代码人生
版权声明:本站是系统测试站点,无实际运营。本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 XXXXXXo@163.com 举报,一经查实,本站将立刻删除。
相关推荐