重做日志-redo log
1、设计思路
可以先说:为什么要引入内存(buffer pool)?
mysql中的数据是存储在硬盘中的,读、写数据都需与磁盘进行交互。如读取数据,首先从磁盘中获取到数据,然后放到内存中,待到下次同样的查询直接从内存中获取;再如,更新数据依然是先从磁盘获取数据存放到内存,然后对内存中的数据更改完毕后,再进行刷盘的操作,以此完成写操作。
对于少量数据,数据库可以接受,但是对于大量数据以及访问量,数据库一时的磁盘IO次数将会大大增加,势必给其带来不少的压力,以至于数据库会崩溃。
为了解决这一问题,我们可以从刷盘处入手,当数据需要更新时,先使用一个文件对更新操作进行记录,然后再更新内存,在适当的时候对数据进行统一的刷盘操作,而这个文件就是redo log,该技术也被称为WAL技术,WAL的全称是Write-Ahead Logging,即先写日志,再写磁盘。该技术主要就是为了减少sql执行期间的数据库io操作次数,并且更新磁盘往往是在Mysql比较闲的时候,这样就大大减轻了Mysql的压力。
此外,当内存中的脏页进行刷盘,而MySQL宕机时,如果没有redo log的话,修改后的数据就会丢失。
2、redo log介绍
首先,提出一个问题:redo log是否对其文件大小有限制?若有限制,当超过其限制时,数据库会做出怎样对应的操作?
解一:redo log文件的大小
InnoDB的redo log是固定大小的,比如可以配置为一组4个文件,每个文件的大小是 1GB,那么这个日志总共就可以记录4GB的操作。并且写redo log是环状写日志的形式,如下图。
- write pos是当前记录的位置,一边写一边后移。
- check point是当前要擦除的位置,也是往后推移并且循环的,擦除记录前要把记录更新到数据文件。
规定:write pos和checkpoint之间的是日志上还空着的部分,可以用来记录新的操作。如果write pos 追上checkpoint,表示日志满了,这时候不能再执行新的更新,得停下来先擦掉一些记录,把 checkpoint推进一下。
总结:有了redo log,InnoDB就可以保证即使数据库发生异常重启,之前提交的记录都不会丢失,这个能力称为crash-safe。
3、产生的 redo log 是直接写入磁盘的吗?
实际上,执行一个事务的过程中,产生的 redo log 也不是直接写入磁盘的,因为这样会产生大量的 I/O 操作,而且磁盘的运行速度远慢于内存。
所以,redo log 也有自己的缓存—— redo log buffer,每当产生一条 redo log 时,会先写入到 redo log buffer,后续在持久化到磁盘如下图:
redo log buffer 默认大小 16 MB,可以通过 innodb_log_Buffer_size 参数动态的调整大小,增大它的大小可以让 MySQL 处理「大事务」是不必写入磁盘,进而提升写 IO 性能。
4、redo log 的刷盘时机?
缓存在 redo log buffer 里的 redo log 还是在内存中,它主要有下面几个刷盘时机:
- MySQL 正常关闭时;
- 当 redo log buffer 中记录的写入量大于 redo log buffer 内存空间的一半时,会触发落盘;
- InnoDB 的后台线程每隔 1 秒,将 redo log buffer 持久化到磁盘。
- 每次事务提交时都将缓存在 redo log buffer 里的 redo log 直接持久化到磁盘