MySQL 为什么需要 redo log?( 二 )


4. redo log 的诞生在正式介绍 redo log 之前,还需要给大家普及一个概念:WAL 。
WAL 全称是 Write-Ahead Logging 中文译作预写日志 。啥意思呢?就是说 MySQL 的写操作并不是立刻更新到磁盘上,而是先记录在日志上,然后在合适的时间再更新到磁盘上,这样的好处是错开高峰期的磁盘 IO,提高 MySQL 的性能 。
配合上前面的 buffer pool 和 change buffer,WAL 就是说在操作 buffer pool 和 change buffer 之前,会先把记录写到 redo log 日志中,然后再去更新 buffer pool 或者 change buffer,这样,即使系统突然崩了,将来也可以通过 redo log 恢复数据 。当然,redo log 本身又分为:

  • 日志缓冲(redo log buffer),该部分日志是易失性的 。
  • 重做日志(redo log file),这是磁盘上的日志文件,该部分日志是持久的 。
那有人说,写 redo log 不就是磁盘 IO 吗?而写数据到磁盘也是磁盘 IO,既然都是磁盘 IO,那干嘛不把直接把数据写到磁盘呢?还费这事!
此言差矣 。
写 redo log 跟写数据有一个很大的差异,那就是 redo log 是顺序 IO,而写数据涉及到随机 IO,写数据需要寻址,找到对应的位置,然后更新/添加/删除,而写 redo log 则是在一个固定的位置循环写入,是顺序 IO,所以速度要高于写数据 。
如前文所说,redo log 涉及到两个东西:redo log buffer 和 redo log file,这两个东西我们分别来介绍 。
4.1 redo log buffer先来说 redo log buffer 。
我们说数据的变化先写入 redo log 中,并不是上来就写磁盘,也是先写到内存中,即 redo log buffer,在时机成熟时,再写入磁盘,也就是 redo log file 。
我们先来看看 redo log buffer 有多大:
MySQL 为什么需要 redo log?

文章插图
 
16777216 ÷ 1024 ÷ 1024 = 16MB
可以看到,这个 redo log buffer 大小刚好是 16MB,如果你觉得这个值有点小,也可以自行修改其大小 。
数据的变更都会首先记录在这块内存中 。小伙伴们知道,MySQL 的增删改,如果我们没有显式的开启事务,MySQL 内部也是有一个事务存在的,当内部这个事务 commit 的时候,redo log buffer 会持久化到磁盘中 。
【MySQL 为什么需要 redo log?】具体来说,有如下几个持久化时机:
  1. innodb_flush_log_at_trx_commit
通过
innodb_flush_log_at_trx_commit 参数来控制持久化时机,该参数默认值为 1,如下图:
MySQL 为什么需要 redo log?

文章插图
 
当然开发者可根据自己的实际需求修改该参数 。该参数有三种取值,含义分别如下:
  • 0:每秒一次,将 redo log buffer 中的数据刷新到磁盘中 。
  • 1:每次 commit 时,将 redo log buffer 中的数据刷新到磁盘中,即只要 commit 成功,磁盘上就有对应的 redo log 日志,这是最安全的情况,也是推荐使用的参数 。
  • 2:每次 commit 时,将 redo log buffer 中的数据刷新到操作系统缓存中,操作系统缓存中的数据每秒刷新一次,会持久化到磁盘中 。
这是第一种 redo log buffer 持久化的时机 。
  1. 当 redo log buffer 的使用量达到 innodb_log_buffer_size 的一半时,将其写入磁盘成为 redo log file 。
  2. MySQL 关闭时,将 redo log buffer 写入磁盘成为 redo log file 。
那如果 redo log buffer 中的数据还没有磁盘,MySQL 就挂了该怎么办?没写入磁盘,说明你还没 commit,既然没 commit,那就数据修改操作都还没有完成,那只能丢了就丢了,如果已经 commit 了,那么数据就会持久化到 redo log file 中,此时即使 MySQL 挂了,将来 MySQL 重启恢复了,数据也是可以被恢复的 。具体的恢复逻辑,就涉及到两阶段提交了,这个松哥在后面的文章中再和大家详细介绍 。
4.2 redo log 落盘还有一个需要大家注意的问题就是 redo log 落盘,落盘的数据从哪里来?是从 redo log 日志中来还是从 buffer pool 中来?
在前面的文章中我们说过:binlog 是一种逻辑日志,他里边所记录的是一条 SQL 语句的原始逻辑,例如给某一个字段 +1,这区别于 redo log 的物理日志,物理日志记录的是在某个数据页上做了什么修改 。
由于 redo log 并没有记录数据页的完整数据,所以正常的落盘其实用不到 redo log,数据落盘的时机到了时,直接拿着将脏页(buffer pool)持久化到磁盘中即可 。


推荐阅读