redolog其实就是想干一件事:当一个事务commit了,那肯定是在内存中改了,但是在磁盘里未必。可能刚提交事务就宕机了,还没来得及写磁盘(并且也不会立刻写的,会隔一段时间才刷)。redolog就是要保证这个一致性。
那乍一想我每次内存更新磁盘就更新不就解决了,但这么粗暴的解决方式肯定有问题的:
- 有时候你只修改了一个页的一个字节,但我却要刷写一个页,因为innoDB以页为单位读写
- 一个事务有很多语句,一个语句有很有可能修改很多页。随机io开销太大了。
Q:那咋整?
A:用redo日志,你提交事务,可以先不随机io修改数据而是先写到磁盘中的一个位置上,这个位置叫redo日志。redolog降低了刷盘频率并且占用的空间非常小。同时它记录了页表空间的id等,刷盘很快。这个就叫WAL(Write-Ahead Logging,日志先行)。并且redolog只记载记录下对磁盘中某某页某某位置数据的修改结果,这样会节省很多磁盘空间。与数据库层的binlog完成一个事务写一次不同,redolog是存储引擎层的,他会在事务执行过程中不断记录。并且尽管redolog是磁盘的一块空间,但写入的过程是顺序的,因为它是一个循环的逻辑空间,如下图所示,需要注意实际上redo日志文件是若干文件组串起来的。
具体工作如下:
其中最重要的是3!,其实这步保证了,其他的都好说了。那redolog的刷盘策略到底是啥呢?其实redolog buffer和redolog file之间还有一层缓冲,叫做文件系统缓存(page cache),这是操作系统为了提升写入效率的一个优化。那这里有三种选择:
- 设置为0 :表示每次事务提交时不进行刷盘操作。(系统默认master thread每隔1s进行一次重做日 志的同步) 第1步:先将原始数据从磁盘中读入内存中来,修改数据的内存拷贝 第2步:生成一条重做日志并写入redo log buffer,记录的是数据被修改后的值 第3步:当事务commit时,将redo log buffer中的内容刷新到 redo log file,对 redo log file采用追加 写的方式 第4步:定期将内存中修改的数据刷新到磁盘中
- 设置为1 :表示每次事务提交时都将进行同步,刷盘操作( 默认值,安全性最好效率差些 )
- 设置为2 :表示每次事务提交时都只把 redo log buffer 内容写入 page cache,不进行同步。由os自 己决定什么时候同步到磁盘文件。
那是如何写入redolog file的呢?也就是说过程是怎样的呢?
首先我们得先知道什么是mtr,也就是Mini-Transaction,即MySQL底层页面中的一次原子访问过程。比如,向某个索引对应的B+树中插入一条记录的过程就是一个Mini-Transaction。一个所谓的mtr可以包含一组redo日志,在进行崩溃恢复时这一组redo日志可以作为一个不可分割的整体。
一个mtr执行过程中可能产生若干条redo日志,这些redo日志是一个不可分割的组,所以其实并不是每生成一条redo日志,就将其插入到log buffer中,而是每个mtr运行过程中产生的日志先暂时存到一个地方,当该mtr结束的时候,将过程中产生的一组redo日志再全部复制到log buffer中。