InnoDB存储引擎通过redo日志机制来保证事务的持久性,当MySQL服务发生异常崩溃时,已经提交的事务修改不会丢失,这就是持久性的核心体现。redo日志记录了数据页的物理修改操作,是InnoDB实现崩溃恢复的关键组件。

什么是redo日志
redo日志是InnoDB存储引擎层产生的日志,属于物理日志,记录了某个数据页上做了什么修改。比如对某个表的某行数据做了更新操作,redo日志会记录对应数据页的修改内容,而不是记录逻辑上的SQL语句。
和binlog不同,binlog是MySQL Server层产生的逻辑日志,记录的是语句的原始逻辑,而redo日志是InnoDB引擎层的物理日志,两者作用场景完全不同。
redo日志的写入机制
redo日志并不是直接写入磁盘的,而是先写入redo log buffer,也就是重做日志缓冲区,这是一块InnoDB在内存中分配的区域,默认大小为16MB。
redo日志的写入流程分为几个阶段:
- 事务执行过程中,产生的redo日志先写入redo log buffer
- 事务提交时,根据配置的刷盘策略,将redo log buffer中的内容写入操作系统的page cache,或者直接刷到磁盘的redo log文件中
- redo log文件是循环写入的,默认有两个文件ib_logfile0和ib_logfile1,写满一个后会切换到另一个,覆盖之前的内容
redo日志刷盘策略
InnoDB通过innodb_flush_log_at_trx_commit参数控制redo日志的刷盘行为,该参数有三个可选值:
| 参数值 | 刷盘行为 | 持久性保证 |
|---|---|---|
| 0 | 事务提交时,redo log buffer的内容每秒写入page cache,同时刷盘一次 | MySQL崩溃可能丢失1秒内的已提交事务 |
| 1 | 事务提交时,redo log buffer的内容直接写入page cache并刷盘 | 完全保证持久性,是默认配置 |
| 2 | 事务提交时,redo log buffer的内容写入page cache,每秒刷盘一次 | 操作系统崩溃可能丢失1秒内的已提交事务 |
redo日志如何保证持久性
当执行一个更新语句时,InnoDB的处理流程如下:
- 执行器调用InnoDB接口,找到对应数据页,如果数据页不在内存中,先从磁盘加载到内存的缓冲池(buffer pool)
- 修改缓冲池中的数据页,生成对应的redo日志,写入redo log buffer
- 事务提交时,根据
innodb_flush_log_at_trx_commit配置,将redo日志刷到磁盘的redo log文件 - 返回事务提交成功的响应给客户端
- 后续InnoDB的后台线程会将缓冲池中修改过的数据页(脏页)刷到磁盘的数据文件中
这个过程中,只要redo日志已经刷到磁盘,即使后续MySQL崩溃,脏页还没刷到磁盘,重启后InnoDB也可以通过redo日志恢复这些修改,保证已提交事务的修改不会丢失,这就是持久性的实现逻辑。
崩溃恢复流程
当MySQL异常重启后,InnoDB会进入崩溃恢复流程,核心就是读取redo日志进行重做:
- 首先定位到redo日志中上次刷盘的检查点(checkpoint)位置,检查点之前的redo日志对应的修改已经刷到数据文件,不需要处理
- 从检查点之后的位置开始,读取redo日志,按照记录的内容重做对应的数据页修改
- 重做完成后,所有已提交事务的修改都恢复到内存中,后续脏页刷盘后数据就完全恢复
代码示例:查看redo日志相关配置
可以通过以下SQL语句查看InnoDB redo日志的相关配置参数:
-- 查看redo日志刷盘策略 SHOW VARIABLES LIKE 'innodb_flush_log_at_trx_commit'; -- 查看redo log buffer大小 SHOW VARIABLES LIKE 'innodb_log_buffer_size'; -- 查看redo log文件大小 SHOW VARIABLES LIKE 'innodb_log_file_size'; -- 查看redo log文件数量 SHOW VARIABLES LIKE 'innodb_log_files_in_group';
redo日志和binlog的区别
很多开发者会混淆redo日志和binlog,两者的核心区别如下:
- 层级不同:redo日志是InnoDB引擎层日志,binlog是MySQL Server层日志,所有存储引擎都会产生binlog
- 日志类型不同:redo日志是物理日志,记录数据页的修改;binlog是逻辑日志,记录SQL语句的原始逻辑
- 写入时机不同:redo日志在事务执行过程中不断写入,binlog在事务提交时一次性写入
- 作用不同:redo日志用于崩溃恢复,保证持久性;binlog用于主从复制和数据备份
在实际的MySQL架构中,为了保证主从复制和数据恢复的一致性,通常还需要开启两阶段提交,协调redo日志和binlog的写入顺序,避免出现数据不一致的问题。