一、什么是redo日志?
如果我们只在内存的 Buffer Pool 中修改了页面,假设在事务提交后突然发生了某个故障,导致内存中的数据都失效了,那么这个已经提交了的事务对数据库中所做的更改也就跟着丢失了,这会导致事务会失去持久性。所以我们需要把修改了哪些东西记录一下。即使之后系统崩溃了,重启之后只要按照上述内容所记录的步骤重新更新一下数据页,那么该事务对数据库中所做的修改又可以被恢复出来,记录内容就是 redo日志。所以redo日志的本质是记录了一下事务对数据库做了哪些修改
redo日志有两个好处:
(1) redo 日志占用的空间非常小
(2) redo 日志是顺序写入磁盘的
二、 redo日志格式
- 简单的redo日志
- 复杂一些的redo日志类型
- redo日志格式小结:redo日志会把事务在执行过程中对数据库所做的所有修改都记录下来,在之后系统奔溃重启后可以把事务所做的任何修改都恢复出来。
三、Mini-Transaction
引出:在执行语句的过程中产生的 redo 日志被设计 InnoDB 的大叔人为的划分成了若干个不可分割的组。举例:有的需要保证原子性的操作会生成多条 redo 日志,比如向某个索引对应的 B+ 树中进行一次悲观插入(插入数据时候发生页分裂)就需要生成许多条 redo 日志。设计 MySQL 的大叔把对底层页面中的一次原子访问的过程称之为一个 Mini-Transaction ,简称 mtr。
四、redo日志的写入过程
- 写入过程:在服务器启动时就向操作系统申请了一大片称之为 redo log buffer 的连续内存空间,翻译成中文就是 redo日志缓冲区 ,我们也可以简称为 log buffer 。这片内存空间被划分成若干个连续的 redo log block ,就像这样:
其中的每个redo log block 中的 log block body部分都是写入redo日志的地方,从左往右依次填满各个redo log block。 注意:并不是每生成一条 redo 日志,就将其插入到 log buffer 中,而是每个 mtr 运行过程中产生的日志先暂时存到一个地方,当该 mtr 结束的时候,将过程中产生的一组 redo 日志再全部复制到 log buffer 中。 - buf_free变量
- lsn变量
概念:设计 InnoDB 的大叔为记录已经写入的 redo 日志量,设计了一个称之为 Log Sequeue Number 的全局变量,简称 lsn
从上边的描述中可以看出来,每一组由mtr生成的redo日志都有一个唯一的LSN值与其对应,LSN值越小,说明
redo日志产生的越早。 - buf_next_to_write变量(可略)
概念:指下一个要被写入磁盘的缓存页的位置。
- flushed_to_disk_lsn变量(一开始与lsn值相同,然后主键开始拉开差距,若某时刻相同,则所有redo日志都刷新到磁盘)
概念:指已经将数据写入磁盘的最后一个LSN。指已经将数据写入磁盘的最后一个LSN
注意:如果两者的值相同时(flushed_to_disk_lsn与lsn),说明log buffer中的所有redo日志都已经刷新到磁盘中了。 - flush链表中的lsn
flush链表中的脏页按照修改发生的时间顺序进行排序,也就是按照oldest_modification代表的LSN值进行排序,被多次更新的页面不会重复插入到flush链表中,但是会更新newest_modification属性的值 - lsn值和redo日志文件偏移量的对应关系
(上面是lsn,下面是磁盘中日志文件偏移量)
五、redo日志文件
- redo日志刷盘时机
(1)log buffer 空间不足时
(2)事务提交时
(3)后台线程不停的刷刷刷
(4)正常关闭服务器时‘
(5)5. checkpoint 时 - redo日志文件组(磁盘中)
概念:MySQL 的数据目录(使用 SHOW VARIABLES LIKE ‘datadir’ 查看)下默认有两个名为 ib_logfile0 和
ib_logfile1 的文件, log buffer 中的日志默认情况下就是刷新到这两个磁盘文件中(可调节)。注意:写的时候会有追尾现象
具体结构:(前2048个字节,存储一些管理信息的。从第2048字节往后是用来存储 log buffer 中的block镜像)
- checkpoint
引出:redo日志只是为了系统奔溃后恢复脏页用的,如果对应的脏页已经刷新到了磁盘,也就是说即使现在系统奔溃,那么在重启后也用不着使用redo日志恢复该页面了,所以该redo日志也就没有存在的必要了,那么它占用的磁盘空间就可以被后续的redo日志所重用(也就是可以光明正大的追尾)。所以,判断某些redo日志占用的磁盘空间是否可以覆盖的依据就是它对应的脏页是否已经刷新到磁盘里。
checkpoint_lsn变量:来代表当前系统中可以被覆盖的 redo 日志总量是多少。
checkpoint:当一个redo日志组所对应的页已经刷新到磁盘中了,那么该日志组产生的redo日志就可以被覆盖了,然后做一次checkpoint_lsn值增加的操作。这个过程称为做一次checkpoint。步骤以下:
步骤二:计算一下当前系统中可以被覆盖的 redo 日志对应的 lsn 值最大是多少。凡是在所有mtr的lsn值小于该节点的oldest_modification值时产生的redo日志都是可以被覆盖掉的。
步骤一:将 checkpoint_lsn 和对应的 redo 日志文件组偏移量以及此次 checkpint 的编号写到日志文件的管理信息