图文结合带你搞懂MySQL日志之Redo Log(重做日志)


  • GreatSQL社区原创内容未经授权不得随意使用,转载请联系小编并注明来源。
  • GreatSQL是MySQL的国产分支版本,使用上与MySQL一致。
  • 作者:KAiTO


往期文章:

  • 图文结合带你搞定MySQL日志之Undo log(回滚日志)
  • 图文结合带你搞懂InnoDB MVCC

导读

前言

请读者注意:本文基于 GreatSQL 8.0.25 & MySQL 5.7.7-RC版本,在 MySQL8.0.30 Redo 发生变化,详情见: MySQL 8.0.30动态redo log初探

前面聊了MySQL中的Undo Log日志和InnoDB中的MVCC,今天一起来学习下Redo Log日志。

事务有4种特性:原子性、一致性、隔离性和持久性(ACID)。那么事务的四种特性到底是基于什么机制实现呢?
  • 事务的隔离性由锁机制实现。
  • 而事务的原子性、一致性和持久性由事务的 Redo 日志和 Undo 日志来保证。

Redo Log称为重做日志,提供再写入操作,恢复提交事务修改的页操作,用来保证事务的持久性。

UNDO LOG称为回滚日志,回滚行记录到某个特定版本,用来保证事务的原子性、一致性。

有的DBA或许会认为 UNDO 是 REDO 的逆过程,其实不然。REDO和UNDO都可以视为是一种恢复操作。

Redo Log:是存储引擎层(InnoDB)生成的日志,记录的是"物理级别"上的页修改操作,比如页号xx、偏移量yyy写入了’zzz’数据。主要为了保证数据的可靠性;

  • 提交,由Redo Log来保证事务的持久化。

Undo Log:是存储引擎层(Innodb)生成的日志,记录的是逻辑操作日志,比如对某一行数据进行了INSERT语句操作,那么Undo Log 就记录一条与之相反的DELETE操作。主要用于事务的回滚(Undo Log 记录的是每个修改操作的逆操作)和一致性非锁定读(Undo Log回滚行记录到某种特定的版本—MVCC,即多版本并发控制)。

Redo Log日志

InnoDB存储引擎是以页为单位来管理存储空间的。在真正访问页面之前需要把在磁盘上的页缓存到内存中的Buffer Pool之后才可以访问。所有的变更都必须先更新缓冲池中的数据,然后缓冲池中的脏页会以一定的频率被刷入磁盘(checkPoint机制),通过缓冲池来优化CPU和磁盘之间的鸿沟,这样就可以保证整体的性能不会下降太快。

为什么需要Redo日志

一方面,缓冲池可以帮助我们消除CPU和磁盘之间的鸿沟,checkpoint机制可以保证数据的最终落盘,然而由于checkpoint并不是每次变更的时候就触发的,而是master线程隔一段时间去处理的。所以最坏的情况就是事务提交后,刚写完缓冲池,数据库宕机了,那么这段数据就是丢失的,无法恢复。

另一方面,事务包含持久性的特性,就是说对于一个已经提交的事务,在事务提交后即使系统发生了崩溃,这个事务对数据库中所做的更改也不能丢失。

那么如何保证这个持久性呢?一个简单的做法:在事务提交完成之前把该事务所修改的所有页面都刷新到磁盘,但是这个简单粗暴的做法有些问题:

  • 修改量与刷新磁盘工作量严重不成比例

有时候我们只修改了某个页面中的一个字节,但是我们知道在InnoDB中是以页为单位来进行磁盘IO的,也就是说我们在该事务提交时不得不将一个完整的页面从内存中刷新到磁盘,我们又知道一个页面默认是16KB大小,只修改一个字节就要刷新16KB的数据到磁盘上显然是太小题大做了(这也就是所谓“写放大”的意思)。

  • 随机Io刷新较慢

一个事务可能包含很多语句,即使是一条语句也可能修改许多页面,假如该事务修改的这些页面可能并不相邻,这就意味着在将某个事务修改的Buffer Pool中的页面刷新到磁盘时需要进行很多的随机IO,随机IO比顺序IO要慢,尤其对于传统的机械硬盘来说。

另一个解决的思路 :我们只是想让已经提交了的事务对数据库中数据所做的修改永久生效,即使后来系统崩溃,在重启后也能把这种修改恢复出来。所以我们其实没有必要在每次事务提交时就把该事务在内存中修改过的全部页面刷新到磁盘,只需要把修改了哪些东西记录一下就好。

比如,某个事务将系统表空间中 第10号页面中偏移量为 100 处的那个字节的值 1 改成 2 。 我们只需要记录一下:将第0号表空间的10号页面的偏移量为 100 处的值更新为 2 。

InnoDB引擎的事务采用了WAL技术(Write-Ahead Logging),这种技术的思想就是先写日志,再写磁盘,只有日志写入成功,才算事务提交成功,这里的日志就是Redo Log。当发生宕机且数据未刷到磁盘的时候,可以通过Redo Log来恢复,保证ACID中的D,这就是Redo Log的作用。

Redo日志记录了什么

为了应对InnoDB各种各样不同的需求,到MySQL 8.0为止,已经有多达 65 种的REDO记录。用来记录这不同的信息,恢复时需要判断不同的 REDO 类型,来做对应的解析。根据 REDO 记录不同的作用对象,可以将这65中 REDO 划分为三个大类:

  • 作用于Page
  • 作用于Space
  • 提供额外信息的Logic类型。

Redo日志的好处、特点

  • 好处
  • Redo日志降低了刷盘频率 Redo日志占用的空间非常小 存储表空间ID、页号、偏移量以及需要更新的值,所需的存储空间是很小的,刷盘快。
  • 特点
  • Redo日志是顺序写入磁盘的 在执行事务的过程中,每执行一条语句,就可能产生若干条Redo日志,这些日志是按照产生的顺序写入磁盘的,也就是使用顺序IO,效率比随机IO快。
  • 事务执行过程中,Redo Log不断记录 Redo Log跟Binlog的区别,Redo Log是存储引擎层产生的,而Binlog是数据库层产生的。假设一个事务,对表做10万行的记录插入,在这个过程中,一直不断的往Redo Log顺序记录,而 Binlog 不会记录,直到这个事务提交,才会一次写入到 Binlog 文件中。

Redo的组成

Redo Log可以简单分为以下两个部分:

  • 重做日志的缓冲 (Redo Log Buffer)
    保存在内存中,是易失的。
    在服务器启动时就向操作系统申请了一大片称之为Redo Log Buffer的连续内存空间,翻译成中文就是Redo日志缓冲区。这片内存空间被划分成若干个连续的Redo Log Block。一个Redo Log Block占用512字节大小。

  • 参数设置innodb_log_buffer_size:

Redo Log Buffer 的大小,默认为 16M ,最大值是4096M,最小值为 1M

mysql> show variables like '%innodb_log_buffer_size%'; +------------------------+----------+ | Variable_name | Value | +------------------------+----------+ | innodb_log_buffer_size | 16777216 | +------------------------+----------+