当前位置: 代码网 > it编程>数据库>Mysql > MySQL redo日志写入磁盘的实现过程

MySQL redo日志写入磁盘的实现过程

2025年06月26日 Mysql 我要评论
1、背景之前我们讲过redo日志类型有很多种,但是要想保证服务器崩溃数据能还原,这些日志还是得存储在磁盘上,接下来我们就来讲解一下redo日志的存储过程。2、redo日志存储过程【1】redo log

1、背景

之前我们讲过redo日志类型有很多种,但是要想保证服务器崩溃数据能还原,这些日志还是得存储在磁盘上,接下来我们就来讲解一下redo日志的存储过程。

2、redo日志存储过程

【1】redo log block

redo日志也是存储在页中的,页的大小为512字节,存储redo日志的页就被称为redo log block,一个redo log block有三部分组成,其组成如图:

在这里插入图片描述

字段含义如下:

字段名字节大小含义
log block header12由4部分组成,存储管理信息
log block body496真正存储redo日志数据的地方
log block trailer4由1部分组成,用于校验正确性

log block header的组成结果如图:

在这里插入图片描述

字段含义如下:

字段名字节大小含义
log_block_hdr_no4每个block的唯一编号
log_block_hdr_data_len2block中已经使用了多少字节,初始就为log block header大小12
log_block_first_rec_group2这个block中第有个mtr(mini-transaction)对应的redo日志组中第一条redo日志偏移量
log_block_checkpoint_no4checkpoint序号

【2】log buffer

redo日志也不是直接写入磁盘,会写入一块连续的内存区域,这块连续的内存就叫log buffer,其结构如图:

在这里插入图片描述

这块连续内存的大小可以通过innodb_log_buffer_size字段查看,单位字节:

mysql> show variables like 'innodb_log_buffer_size';
+------------------------+----------+
| variable_name          | value    |
+------------------------+----------+
| innodb_log_buffer_size | 16777216 |
+------------------------+----------+
1 row in set, 1 warning (0.00 sec)

【3】buf_free

一个事务可以有多个mtr,一个mtr可以有多个redo日志记录,将redo日志写入log buffer中时,时间上是写入block中的log block body部分,当一个block写满也就是log block body写满时,就去写连续的下一个block,可以写入redo日志的空闲log buffer的最小偏移量就叫buf_free,所以每次我们要写入redo日志只需要找到buf_free偏移量,就可以知道在log buffer的哪个地方写redo日志了,可以如图表示:

在这里插入图片描述

【4】redo日志刷盘时机

log buffer空闲有限,所以也需要将redo日志写到磁盘再释放空间,用于写入新的redo日志,从内存刷到磁盘的时机有如下几种:

  • 1、log buffer空间不足
  • 2、事务提交时
  • 3、后台线程定时刷
  • 4、正常关闭服务器
  • 5、checkpoint时

【5】redo日志文件组

从log buffer刷新到磁盘中的redo日志是存储在ib_logfile0ib_logfile1ib_logfilen文件中,这些文件就叫redo日志文件组,可以通过配置文件指定此组文件的目录、大小、数量。

查看目录方式如下:

mysql> show variables like 'innodb_log_group_home_dir';
+---------------------------+--------------------------------------------+
| variable_name             | value                                      |
+---------------------------+--------------------------------------------+
| innodb_log_group_home_dir | /xxx/data |
+---------------------------+--------------------------------------------+
1 row in set (0.002 sec)

查看大小方式如下,单位字节:

mysql> show variables like 'innodb_log_file_size';
+----------------------+----------+
| variable_name        | value    |
+----------------------+----------+
| innodb_log_file_size | 50331648 |
+----------------------+----------+
1 row in set, 1 warning (0.01 sec)

查看数量方式如下:

mysql> show variables like 'innodb_log_files_in_group';
+---------------------------+-------+
| variable_name             | value |
+---------------------------+-------+
| innodb_log_files_in_group | 2     |
+---------------------------+-------+
1 row in set, 1 warning (0.00 sec)

查看一下ib_logfile文件如下:

[root@xxx xxx]# ls /xxx/data/ | grep 'ib_log'
ib_logfile0
ib_logfile1

写文件是ib_logfile0到ib_logfile1循环写入,当ib_logfile1写满时就重新从ib_logfile0重新写入。

【6】ib_logfile文件格式

和log buffer的组成结构一样,ib_logfile也是由连续的512字节大小的block组成,有区别的是ib_logfile的前四个block用了存储管理信息,后面的block才用来存储redo日志,其存储过程可以如图表示:

在这里插入图片描述

redo日志文件前四个block分别为log file header、checkpoint1、未使用、checkpoint2,checkpoint1和checkpoint2是一样的,接下来我们就来讲一下log file header和checkpoint。

log file header结构如下:

在这里插入图片描述

其字段含义为:

字段字节大小含义
log_header_format4redo日志版本
log_header_pad14无用
log_header_start_lsn8标记redo日志文件开始的lsn值,也就是第5个block开始对应的lsn值
log_header_creator32标记redo日志的创建者
log_block_checksum4本block的校验值

checkpoint结构如下:

在这里插入图片描述

其字段含义为:

字段字节大小含义
log_checkpoint_no8服务器每做一次checkpoint,该值就加1
log_checkpoint_lsn8服务器做checkpoint结束时对应的lsn值,系统崩溃恢复时从该值开始
log_checkpoint_offset8上个属性中lsn值在redo日志文件组中的偏移量
log_checkpoint_log_buf_size8服务器在做checkpoint时对应的log buffer大小
log_block_checksum4block的校验值

【7】log sequeue number

log buffer中,innodb为已经写入的redo日志量用个全局变量log sequeue number表示,也叫日志序列号,简称lsn,lsn的初始值为8704,但是block真正写redo日志的是中间的body部分,所以初始的lsn值需要加上第一个block的log block header(12字节)的大小得到初始的lsn值为8716,需要注意后续写入的redo日志如果占用了几个block,计算lsn就需要加上log block header和log block trailer。

【8】flushed_to_disk_lsn

lsn是标记log buffer中已经写入redo日志的量,不关心log buffer上的redo日志是否刷新到磁盘上也就是ib_logfile中,所以innodb中提供了flushed_to_disk_lsn的全局变量来标识log buffer中已经被刷到磁盘的量。

【9】flush链表中的lsn

当我们修改一条数据可能会产生以下流程,首先会产生多个mtr,将这些mtr对应的redo日志组写到log buffer中,然后修改buffer pool中的页,最后再将修改的页对应的控制块加入flush链表,控制块中有个两个记录lsn的属性,oldest_modification和newest_modification,其属性含义如下:

属性名含义
oldest_modification控制块对应的页被修改起始对应的lsn值
newest_modification控制块对应的页被修改结束对应的lsn值

需要注意的是多个mtr修改相同的页,不会修改页对应的控制块在链表中的位置,但是会更新newest_modification属性的值。

【10】checkpoint

innodb中提出了一个全局变量checkpoint_lsn,用来表示redo日志文件中小于该值的部分都可以被覆盖,checkpoint指的是buffer pool中的脏页被刷新到磁盘,这时脏页对应的redo日志就可以被覆盖了,我们就能计算一个checkpoint_lsn值这个过程。

innodb中还有一个checkpoin_no的变量,每执行一次checkpoint,该值就会加1。

前面讲过checkpoint的属性就会包含:checkpoint_lsn、checkpoint_no、checkpoint_lsn对应的偏移量,至于这些属性是存储在checkpoint1还是checkpoint2中,是根据checkpoint_no是奇数还是偶数,如果是奇数就写到checkpoit2中,偶数就写checkpoint1中。

【11】系统中的lsn值

我们可以查看系统中的lsn值,可以通过如下命令去查看:

mysql> show engine innodb status\g;
...
---
log
---
log sequence number          20993334
log buffer assigned up to    20993334
log buffer completed up to   20993334
log written up to            20993334
log flushed up to            20993334
added dirty pages up to      20993334
pages flushed up to          20993334
last checkpoint at           20993334
log minimum file id is       6
log maximum file id is       6
25 log i/o's done, 0.00 log i/o's/second
...

其字段含义为:

字段名含义
log sequence number当前redo日志中lsn的最大值,表示所有修改数据的操作产生的日志序列号,该值会随着日志的写入逐渐增大
log buffer assigned up tolog buffer中被分配到的lsn值,与log sequence number相同
log buffer completed up tolog buffer中准备好写磁盘的lsn值,与log sequence number相同
log written up to已经写到redo日志文件的日志序列号
log flushed up to已经刷新到磁盘的redo日志序列号
added dirty pages up to已添加到脏页列表的页面的lsn值
pages flushed up to已经刷新到磁盘脏页的lsn值
last checkpoint at当前checkpoit_lsn的值
log minimum file id isredo日志文件的最小文件id
log maximum file id isredo日志文件的最大文件id

【12】innodb_flush_log_at_trx_commit

redo日志刷新到磁盘的方式由innodb_flush_log_at_trx_commit控制,刷新方式有3种,分别为:

innodb_flush_log_at_trx_commit值刷新方式
0事务提交时不立即刷新redo日志到磁盘,由后台线程去刷新到磁盘,如果服务器挂了,后台线程没及时将redo日志刷新到磁盘,事务对该页面的修改就会丢失
1事务提交时就将redo日志同步到磁盘
2事务提交时将redo日志写入log buffer,不需要刷新到磁盘,当数据库挂,操作系统挂也能保证持久性,数据库和操作系统都挂就保证不了持久性了

【13】崩坏是redo日志恢复

redo日志的恢复过程如下:

1、确定恢复的起点,也就是checkpoint_lsn,

2、确定恢复的终点,也就是ib_logfile中block未写满的位置,

3、从checkpoint_lsn恢复页时,如果页的fil_page_lsn值,也就是newest_modification的值如果大于checkpoint_lsn,说明该页已经恢复,直接跳过,如果小于checkpoint_lsn,就需要读取redo日志进行恢复。

3、总结

redo日志是innodb使用崩溃恢复的核心机制,通过物理日志、顺序写入和checkpoint机制,保证事务的持久性并且提高了数据库的性能。

以上为个人经验,希望能给大家一个参考,也希望大家多多支持代码网。

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2025  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com