InnoDB存储引擎——redo log

redo log 作用

事务有一个重要特性:持久性,意思是说,只要事务提交成功,那么对数据库的修改就被永久保存了下来。怎么来保证持久性呢?
简单的做法是在每次事务提交的时候,将该事务涉及到的数据页全刷回磁盘,但是这么做会导致严重的性能问题,主要体现在以下两点:

  • InnoDB 中是以页为单位进行磁盘IO的,一个事务的修改可能只是修改数据页里的几个字节,这时候将整个数据页全部刷磁盘的话,太浪费资源了
  • 一个事务的修改可能涉及多个数据页,并且这些数据页在物理上并不连续,使用随机IO写入性能差

为了解决这些问题,MySQL 设计了 redo log,具体来说就是只记录事务对数据页做了哪些修改。然后在适当时机将数据刷回磁盘

redo log 概念

redo log 分为2部分,一部分是内存中的日志缓存(redo log buffer),另一部分是磁盘上的日志文件(redo log file)
MySQL 每执行一条DML语句,先将记录写入 redo log buffer,后续某个时间点再一次性将多个操作记录写到redo log file。这种先写日志,再写磁盘的技术就是 MySQL 中经常说到的 WAL(write ahead logging)技术。
在计算机操作系统中,用户空间下的缓冲区数据一般情况下是无法直接写入磁盘的,中间必须经过操作系统内核空间缓冲区(os buffer),即操作系统缓存
因此,redo log buffer 写入 redo log file实际上是先写入 os buffer,然后再通过系统调用 fsync() 将其刷到磁盘中
在这里插入图片描述
MySQL 支持三种将 redo log buffer 写入 redo log file 的时机,可以通过 innodb_flush_log_at_trx_commit 参数进行配置

redo log 刷盘策略

redo log刷盘主要通过2个参数来配置

  • innodb_flush_log_at_trx_commit :刷盘策略,默认值为 1
    • 1(实时写实时刷):默认值,表示当一个事务提交时,立即将redo log buffer 写入os buffer 并调用 fsync() 刷入磁盘,保证数据不丢失
    • 0(延时写):表示事务提交时不会将 redo log buffer 写入 os buffer,而是每隔 innodb_flush_log_at_timeout 时间写入 os buffer 并调用 fsync()刷入磁盘,如果数据库宕机,会损失 innodb_flush_log_at_timeout 时间的数据
    • 2(实时写延时刷):表示redo log buffer 数据在一个事务提交后,写入 os buffer,每隔 innodb_flush_log_at_timeout 时间调用 fsync() 刷入磁盘
  • innodb_flush_log_at_timeout:后台线程定时刷盘的时间,单位:秒,默认值:1
    在这里插入图片描述
redo log记录形式

redo log在磁盘上存储的文件名为 ib_logfile_1和 ib_log_file_2,采用循环写的方式,当写到结尾时,会回到开头循环写日志。
在这里插入图片描述
write pos:表示 redo log 当前记录的 LSN(日志序列号) 位置
check point:表示数据页更改记录刷盘后对应redo log所处的 LSN 位置,上一次刷盘的位置
write pos 到 check point 之间的部分是 redo log 空闲的部分,可以记录新的数据
check point 到 write pos 之间的部分是 redo log 待刷盘的数据页更改记录
当write pos追上 check point 时,会先推动 check point 向前移动,空出位置再记录新的日志

数据恢复情况

  • 启动innodb的时候,不管上次是正常关闭还是异常关闭,总数会进行恢复操作。因为 redo log 记录的是数据页的物理变化,因此恢复的速度比逻辑日志(如binlog)要快很多
  • 重启innodb时,首先会检查磁盘中数据页的LSN,如果数据页的LSN小于redo log日志中的LSN,则会从 check point开始恢复
  • 在宕机前正处于check point的刷盘过程,且数据页的刷盘进度超过了日志页的刷盘进度,此时会出现数据页中记录的LSN大于日志中的LSN,这是超出日志进度的部分将不会重做,因为这本身就表示已经做过的事情了,无需再重新做
redo log日志格式

redo log记录某个表空间某个数据页某个偏移量的位置修改了几个字节的值,修改的值是多少
表空间号 + 数据页号 + 偏移量位置 + 修改值长度 + 具体的值 组成

一条普通redo log日志数据格式:
在这里插入图片描述
一条redo log日志数据格式(修改的值很大)
在这里插入图片描述
在 redo log buffer 中,并不是存的一条条 redo log 记录,而是存的 redo log block,每个redo log block里包含多条 redo log 记录。
在这里插入图片描述
一个 redo log block 大小为 512 字节,由三部分组成:

  • header:头部,12字节
  • body:记录多行 redo log 日志,496字节
  • trailer:块尾,4字节

header里又包含了4部分

  • block_no:块编号,4字节
  • data length:已经写入的数据长度,2字节
  • first record group:第一个日志分组偏移量,2字节,
  • checkpoint no:4字节

redo log block 刷盘策略

  • redo log buffer日志占据redo log buffer总容量一半
  • 一个事务提交
  • 后台线程定时刷新,每隔1秒将buffer刷到磁盘
  • MySQL关闭的时候
刷盘策略性能比较
  • (默认)配置1, 事务提交, 写os buffer且刷盘
mysql> show variables like '%innodb_flush_log%';
+--------------------------------+-------+
| Variable_name                  | Value |
+--------------------------------+-------+
| innodb_flush_log_at_timeout    | 1     |
| innodb_flush_log_at_trx_commit | 1     |
+--------------------------------+-------+
2 rows in set, 1 warning (0.00 sec)

mysql> call p_data();
Query OK, 1 row affected (12.05 sec)
  • 配置2, 事务提交, 写os buffer, 异步定时刷盘
mysql> set global innodb_flush_log_at_trx_commit=2;
mysql> show variables like '%innodb_flush_log%';
+--------------------------------+-------+
| Variable_name                  | Value |
+--------------------------------+-------+
| innodb_flush_log_at_timeout    | 1     |
| innodb_flush_log_at_trx_commit | 2     |
+--------------------------------+-------+
2 rows in set, 1 warning (0.00 sec)

mysql> call p_data();
Query OK, 1 row affected (1.44 sec)
  • 配置0, 事务提交, 异步写 os buffer, 异步刷盘
mysql> set global innodb_flush_log_at_trx_commit=0;
mysql> show variables like '%innodb_flush_log%';
+--------------------------------+-------+
| Variable_name                  | Value |
+--------------------------------+-------+
| innodb_flush_log_at_timeout    | 1     |
| innodb_flush_log_at_trx_commit | 0     |
+--------------------------------+-------+
2 rows in set, 1 warning (0.00 sec)

mysql> call p_data();
Query OK, 1 row affected (0.32 sec)

可以看到,
配置为1时,每当事务提交后会写 os buffer 并且刷盘,所以耗时最长,花费12.05秒(数据不丢失)
配置为2时,事务提交后只写os buffer,异步刷盘,花费1.44秒(数据有丢失风险)
配置为0时,事务提交后,异步写os buffer和刷盘,花费0.32秒(数据有丢失风险)

参考文章
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值