redo log-学习

140 阅读3分钟

参考文章:

MySQL的崩溃恢复到底是怎么回事: developer.aliyun.com/article/919…

背景

保证持久化。简单做法,在事物提交之前把内存里的改动同步到磁盘即可,存在的问题:

  • 如果只修改了一个字段,一个字节改动就把页数据(18k)刷到磁盘,太浪费
  • 随机性修改,一个事物中可能涉及到多个不连续的页,要进行很多随机IO

redo log的思路,崩溃重启后可以恢复数据也相当于保证了持久性,每次修改记录会保存一条redo log

  • redo log结构:type、spaceID、pageNumber、data。
  • row_id例子,简单redo_log的结构增一条记录,各个树,文件header等修改,复杂redo_log的例子(保存底层函数参数)
  • redo日志只是系统崩溃时用来恢复脏页的,如果脏页都已经刷盘了,那么就不需要redo日志了,redo日志可以被覆盖了。

log buffer

不会直接将redo log写入log file,先写到Buffer Pool中的 log Buffer中,再由一些机制同步到log file。

log buffer 同步到log file:

  • log buffer空间不足时
  • 事物提交时
  • 系统线程每秒刷新到log file
  • 正常关闭服务时
  • checkpoint时

flush链表

  • 在buffer pool的页被编辑过,不会立即同步磁盘,先记录redo log日志后放到flush链表,等待刷盘操作。
  • o-m、n-m熟悉:第一次修改的lsn,最新一次修改的lsn
  • 刷盘操作: a。正常关闭时 b。系统线程master thread 每秒将flush中的脏页刷新到磁盘 c。缓存页不够用时

checkpoint机制

  • checkpoint 与 刷新flush链表的线程(异步)是两回事

  • checkpoint时机:

    • 固定时间线程刷新,每1/10秒
    • log file空间不足时
    • 缓存页空间不足时,LRU剔除最少使用的页,如果是脏页,执行checkpoint
    • 脏页比例过大,75%
  • checkpoint步骤:

    • 找到flush链表中,o-m最小的控制块,o-m就是最新的checkpoint_lsn
    • 将checkpoint_lsn同步到log_file的管理信息中
  • 好处: 重启时只恢复最新的checkpoint,可以缩短崩溃恢复时间,也就是重启时间。 对log buffer中的脏页、redo log 中的日志做瘦身

lsn

  • 日志序列号,初始值8704,mtr后增加: 实际产生的日志量(一个字节代表1) + log block head + log block tail。
  • lsn越小,代表日志产生越早

flush_to_disk_lsn

redo log 是先到Buffer Pool的 log buffer再到磁盘的log file,其中lsn是当前已经产生的日志量,flush_to_disk_lsn是已经刷新到log file的日志量

checkpoint_lsn

log file中小于 checkpoint_lsn_offset的都可以进行覆盖

可以使用 SHOW ENGINE INNODB STATUS; 查看lsn、flush_to_disk_lsn、checkpoint_lsn各参数值。

log file 与 lsn偏移量关系

lsn默认值8704,log file 默认开始的偏移量是2048,lsn在log file中的偏移量: 当前lsn - 8704 + 2048

崩溃恢复

崩溃恢复,就是MySQL重启时照着redo log中的最后一次Checkpoint之后的日志回放一遍

  1. 确认恢复起点 checkpoint_lsn之后的日志

  2. 确认恢复终点 log block header,记录了使用多少空间时,不足512kb就认为是终点

  3. 崩溃恢复优化

    • 统一处理redo日志:表空间号+页号作为key,redo日志集合作为value
    • 跳过已经刷新到磁盘的页: checkpoint_lsn之后的日志,后台线程不断的从flush链表中刷盘,可能有一部分已被刷盘了,没必要再执行。 如何确认的:页头FileHeader中有一个FIL_PAGE_LSN属性,记录最近一次修改页面的lsn值(控制块的n-m),如果checkpoint_lsn小于页记录的lsn则不需要刷

image.png