分享

MySQL Redo 日志

 新用户73336046 2024-01-08 发布于浙江

redo日志对于事务提交后,数据绝对不会丢失的意义

在我们执行增删改操作的时候,首先会在Buffer Pool中更新缓存页,在更新完Buffer Pool中的缓存页之后,必须要写一条redo log,这样才能记录下来我们对数据库做的修改。

redo log可以保证我们事务提交之后,如果事务中的增删改SQL语句更新的缓存页还没刷到磁盘上去,此时MySQL宕机了,那么MySQL重启过后,就可以把redo log重做一遍,恢复出来事务当时更新的缓存页,然后再把缓存页刷到磁盘就可以了。

redo log本质是保证事务提交之后,修改的数据绝对不会丢失的。

我们都知道,执行增删改SQL语句的时候,都是针对一个表中的某些数据去执行的,此时的话,首先必须找到这个表对应的表空间,然后找到表空间对应的磁盘文件,接着从磁盘文件里把你要更新的那批数据所在的数据页从磁盘读取出来,放到Buffer Pool的缓存页里去,如下图所示:

接着实际上你的增删改SQL语句就会针对Buffer Pool中的缓存页去执行你的更新逻辑,比如插入一行数据,或者更新一行数据,或者是删除一行数据。

其实更新缓存页的时候,会更新free链表、flush链表、lru链表,然后有专门的后台IO线程,不定时的根据flush链表、lru链表,会把你更新过的缓存页刷新回磁盘文件的数据页里去,如下图所示:

这个机制最大的漏洞就在于万一你一个事务里有增删改SQL更新了缓存页,然后事务提交了,结果万一你还没来得及让IO线程把缓存页刷新到磁盘文件里,此时MySQL宕机了,然后内存数据丢失了,你事务更新的数据就丢失了。

但是也不可能每次事务一提交,就把事务更新的缓存页都刷新回磁盘文件里去,因为缓存页刷新到磁盘文件,是随机磁盘读写,性能是相当的差,这会导致数据库性能和并发能力都很弱。

所以才会引入redo log机制,这个机制就是说,你事务提交的时候,绝对是保证把你对缓存页做的修改以日志的形式,写入到redo log日志文件里去的。

这种日志大致的格式如下,对表空间xx中的数据页xx中的偏移量为xxxx的地方更新了数据xxxx,如下图所示:

只要你事务提交的时候保证你做的修改以日志形式写入redo log日志,那么哪怕此时机器突然宕机了,也没关系。

因为MySQL重启之后,把之前事务更新过做的修改根据redo log在Buffer Pool里重做一遍就可以了,就可以恢复出来当时事务对缓存页做的修改,然后找时机再把缓存页刷入磁盘文件里去。

事务提交的时候把修改过的缓存页都刷入磁盘,跟事务提交的时候把做的修改的redo log都写入日志文件,不是都写磁盘么?差别在哪里?

实际上,如果把修改过的缓存页都刷入磁盘,缓存页一个就是16kb,数据比较大,刷入磁盘比较耗时,而且可能就修改了缓存页里的几个字节的数据,难道就把完整的缓存页刷入磁盘吗?而且缓存页刷入磁盘是随机写磁盘,性能是很差的,因为一个缓存页对应的位置可能在磁盘文件的一个随机位置,比如偏移量为45336这个地方。

但是如果是写redo log,一行redo log可能就占据几十个字节,就包含表空间号、数据页号、磁盘文件偏移量、更新值,这个写入磁盘速度很快。

此外,redo log写日志,是顺序写入磁盘文件,每次都是追加到磁盘文件末尾去,速度也是很快的。所以提交事务的时候,用redo log的形式记录下来你做的修改,性能会远远超过刷缓存页的方式,这也可以让数据库的并发能力更强。

在Buffer Pool执行完增删改之后,写入日志文件的redo log长什么样?

redo log里本质上记录的就是在对某个表空间的某个数据页的某个偏移量的地方修改了几个字节的值,具体修改的值是什么,他里面需要记录的就是表空间号+数据页号+偏移量+修改几个字节的值+具体的值。

所以根据你修改了数据页里的几个字节的值,redo log就划分为了不同的类型,MLOG_1BYTE类型的日志指的就是修改了1个字节的值,MLOG_2BYTE类型的日志指的就是修改了2个字节的值,以此类推,还有修改了4个字节的值的日志类型,修改了8个字节的值的日志类型。

当然如果要是一下子修改了一大串的值,类型就是MLOG_WRITE_STRING,就是代表你一下子在哪个数据页的某个偏移量的位置插入或者修改了一大串的值。

所以其实一条redo log看起来大致的结构如下所示:

日志类型(就是类似MLOG_1BYTE之类的),表空间ID,数据页号,数据页中的偏移量,具体修改的数据

大致就是一条redo log中依次排列上述的一些东西,这条redo log表达的语义就很明确了,他的类型是什么,类型就告诉了你他这次增删改操作修改了多少字节的数据;

然后在哪个表空间里操作的,这个就是跟你SQL在哪个表里执行的是对应的;接着就是在这个表空间的哪个数据页里执行的,在数据页的哪个偏移量开始执行的,具体更新的数据是哪些。

有了上述信息,就可以精准完美地还原出来一次数据增删改操作做的变动了。

只不过如果是MLOG_WRITE_STRING类型的日志,因为不知道具体修改了多少字节的数据,所以其实会多一个修改数据长度,就告诉你他这次修改了多少字节的数据,如下所示他的格式:

日志类型(就是类似MLOG_1BYTE之类的),表空间ID,数据页号,数据页中的偏移量,修改数据长度,具体修改的数据

彩蛋

    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多