Redo Log介绍
Redo Log是一种基于物理格式的日志。它记录的是对数据库物理页面(Page)所做的修改,而不是逻辑上的SQL语句。
- 物理格式:它记录的是“在哪个数据文件的哪个页面的哪个偏移量上,做了什么值的修改”。这种记录方式非常紧凑和高效。
- 循环写入:Redo Log文件不是无限增长的。它是由多个固定大小的文件组成的环形日志组(比如
ib_logfile0,ib_logfile1)。当写到最后一个文件的末尾时,会重新回到第一个文件开始覆盖写。 - 幂等性:由于是物理日志,重放Redo Log的操作是幂等的。即使因为某种原因重复执行了同一条Redo Log记录,对数据页的结果也不会产生影响。
为什么需要Redo Log
Redo Log的核心目的是解决一个性能和可靠性之间的矛盾,这个技术方案被称为WAL(Write-Ahead Logging,预写日志)。
-
性能问题:数据库的数据最终是存储在磁盘上的。如果每次事务提交,我们都必须把所有修改过的数据页(Data Page)都从内存刷回到磁盘,那么会产生大量的随机I/O。随机I/O是非常慢的,这会极大地拖慢数据库的性能。
-
WAL解决方案:InnoDB引入了Redo Log来解决这个问题。它的工作流程是:
- 当事务修改数据时,它首先修改的是内存中的数据页(Buffer Pool)。
- 同时,它会将这次修改的“物理操作”记录到Redo Log Buffer(一块内存区域)中。
- 当事务提交时,它不需要立即将数据页刷盘,而只需要保证将对应的Redo Log记录从Redo Log Buffer刷到磁盘上的Redo Log文件中。
- 这个Redo Log的刷盘操作是顺序I/O,速度远快于数据页的随机I/O。
-
带来的好处:
- 保证了事务的持久性(Durability):只要事务提交时Redo Log成功写入磁盘,那么即使数据库此时宕机,内存中的数据页修改全部丢失,我们也能在重启后通过重放Redo Log来恢复这些修改,保证已提交的事务永不丢失。
- 提升了性能:将事务提交时的大量随机I/O操作,转换成了一次或几次高效的顺序I/O操作,极大地提升了数据库的吞吐量。真正的数据页刷盘(称为“刷脏”)可以由后台线程异步、批量地进行。
Redo Log的工作流程(两阶段提交)
Redo Log的写入过程非常精细,涉及到两个关键的指针和一块内存缓冲区:
write pos: 当前记录的位置,一边写一边后移。check point: 当前要擦除的位置,也是一边擦除一边后移。Log Buffer: Redo Log的内存缓冲区。
当事务提交时,为了保证Binlog和Redo Log之间的一致性(这对于主从复制和数据恢复至关重要),InnoDB使用了内部的两阶段提交(Two-phase Commit)机制:
-
Prepare阶段:
- 当执行
COMMIT时,InnoDB首先会将该事务的Redo Log记录写入文件系统缓存,并打上一个“prepare”标记。 - 然后通知MySQL Server层,可以写入Binlog了。
- 当执行
-
Commit阶段:
- MySQL Server层接收到通知后,将该事务的Binlog写入磁盘。
- Binlog写入成功后,Server层会再调用InnoDB的接口,告诉它可以真正提交事务了。
- InnoDB收到这个最终确认后,才会在Redo Log中写入一个“commit”标记,代表事务的真正完成。
两阶段提交的重要性:
这个机制保证了任何一个事务,要么它的Redo Log和Binlog都完整存在,要么就都没有。 * 如果数据库在Redo Log prepare之后、Binlog写入前宕机:重启后,InnoDB发现这个Redo Log只有prepare标记没有commit标记,它会去查询Binlog中是否有对应的事务记录。发现没有,就会回滚这个事务。 * 如果数据库在Binlog写入之后、Redo Log commit前宕机:重启后,InnoDB发现这个Redo Log有prepare标记,并且在Binlog中也能找到对应的事务,它就会认为这个事务是需要被提交的,会继续完成Redo Log的commit操作。
Redo Log与Binlog的区别
| 特性 | Redo Log | Binlog |
|---|---|---|
| 所属层次 | InnoDB引擎层 | MySQL Server层 |
| 日志格式 | 物理日志(数据页的修改) | 逻辑日志(SQL语句或行变更) |
| 写入方式 | 循环写入 | 追加写入,写满一个文件换下一个 |
| 核心作用 | 保证事务持久性,实现崩溃恢复 | 实现主从复制和数据恢复 |
| 幂等性 | 是 | 不一定(STATEMENT格式下) |