MySQL InnoDB引擎核心日志解析:Redo Log、Undo Log与两阶段提交

键盘旁的猫
键盘旁的猫
发布时间:2026-10-16| 6人浏览过
原创

MySQL InnoDB引擎通过Redo Log和Undo Log分别保障事务的持久性与原子性/一致性。Redo Log利用预写式日志技术减少随机IO并支持崩溃恢复,其安全性由innodb_flush_log_at_trx_commit参数控制;Undo Log记录历史版本以支持回滚与MVCC读取。为确保Redo Log与Binlog在崩溃恢复时的逻辑一致,InnoDB采用两阶段提交协议。

InnoDB缓冲池与Redo Log

InnoDB引擎以页(Page)为单位进行数据存储。为了提升读写性能,所有的增删改查操作都会先将数据页从磁盘加载到内存中的buffer pool中。在buffer pool中对数据进行修改后,后台线程会定期将修改过的“脏页”异步刷新回磁盘。

这种设计主要基于以下考量:

  • 避免随机I/O:直接修改磁盘数据会导致大量的随机写操作,消耗极大的系统资源。
  • 利用顺序I/O:通过在内存中操作,随后批量或顺序写入磁盘,提高了吞吐量。

为何需要Redo Log?

尽管有buffer pool加速,但内存中的数据在系统意外宕机时可能来不及刷入磁盘,导致已提交的数据丢失,破坏了事务的持久性(D)。为此,InnoDB引入了Redo Log(重做日志):

  • 定义:Redo Log是物理日志,记录的是“在某数据页上做了什么修改”,属于InnoDB存储引擎层独有。
  • 机制:当事务修改数据时,除了更新buffer pool,还会立即生成一条Redo Log追加写入磁盘。这样即使内存数据未刷盘,重启后也可根据Redo Log恢复已提交的修改。
  • 优势:Redo Log采用追加写(顺序I/O),相比随机写更高效且占用空间小。

Redo Log的执行流程

一个典型的更新操作大致经历以下步骤:

  1. 读取数据:将原始数据从磁盘读入内存buffer pool。
  2. 修改与记录:修改内存副本产生脏数据,同时生成Redo Log信息并写入redo log buffer(内存区域)。
  3. 刷盘持久化:事务提交时,根据配置策略将redo log buffer内容刷新到磁盘上的redo log file(文件),通常采用追加写模式。
  4. 刷脏页:后台线程在适当时机将buffer pool中的脏页同步到磁盘。

这里体现了WAL(Write-Ahead Logging,预写式日志)的核心思想:在任何数据页被写入磁盘之前,相应的日志必须先持久化到磁盘。

Redo Log刷盘策略配置

Redo Log的可靠性取决于其在内存buffer中驻留的时间长短。通过参数 innodb_flush_log_at_trx_commit 可以控制事务提交时的刷盘行为:

  • 值为 0(默认非生产环境可选):每秒调用一次OS刷盘操作。如果宕机,最多丢失1秒的数据。性能最高,但最不安全。
  • 值为 1(数据库默认值):每次事务提交都强制同步刷新Redo Log Buffer到磁盘。保证最高的数据安全性,但性能开销最大。
  • 值为 2:每次事务提交只刷新到操作系统(OS)的内核缓冲区,不直接刷盘。具体何时由OS决定。兼顾了部分性能,但如果OS崩溃可能导致丢失最后一个事务的日志。

其他关键参数

  • innodb_log_group_home_dir:Redo Log文件组所在的目录,默认为数据库数据目录。
  • innodb_log_files_in_group:Redo Log文件个数,默认为2个(ib_logfile0, ib_logfile1等)。
  • innodb_log_file_size:单个Redo Log文件的大小,默认48M。较大的日志文件可以减少检查点频率,提高吞吐,但会增加崩溃恢复时间。

Undo Log与事务一致性

Undo Log主要用于两个方面:提供事务回滚和实现MVCC(多版本并发控制)。

功能详解

  • 事务回滚(原子性):如果事务执行过程中发生错误或显式执行ROLLBACK,或者在长事务中被中断,InnoDB需要根据Undo Log中的旧值将修改撤销,确保事务要么全部完成,要么完全不发生。
  • MVCC快照读(一致性):当其他事务正在锁定某行记录时,当前事务可以通过Undo Log找到该行的历史版本数据,从而实现不加锁的“快照读”(如普通的SELECT语句)。

注意:单纯的SELECT操作不会产生Undo Log,只有INSERT、UPDATE、DELETE会产生。

Undo Log的类型

根据操作类型不同,Undo Log分为两类:

  1. Insert Undo Log:由INSERT操作产生。因为新插入的数据对刚开启的事务之前的事务不可见,所以在事务提交后可以直接删除,无需经过purge(清理)线程处理。
  2. Update Undo Log:由UPDATE和DELETE操作产生。由于这些数据可能对其他已开启的事务可见(用于MVCC),所以不能立即删除。它们会被放入undo log链表中,等待purge线程在确认无事务引用后再物理删除。

Undo Log结构示例

InnoDB的行记录中包含几个隐藏列:

  • DB_ROW_ID:隐藏主键ID。
  • DB_TRX_ID:最近修改该行的事务ID。
  • DB_ROLL_PTR:指向该行最新版本Undo Log的回滚指针。

具体生成过程

场景一:INSERT操作

begin;
INSERT INTO user (name) VALUES ('tom');

此时生成一条Insert Undo Log。如果回滚,只需根据主键删除该行即可。生成的Undo Log记录了指针,指向之前的版本。

场景二:UPDATE操作(非主键字段)

UPDATE user SET name='Sun' WHERE id=1;

这会生成一条Update Undo Log,记录修改前的值(即'name='Tom'')。新的Undo Log链接到旧的版本上,形成版本链。

场景三:UPDATE操作(涉及主键变更)

UPDATE user SET id=2 WHERE id=1;

由于InnoDB聚簇索引按主键排序,修改主键相当于“先删除原记录(id=1),再插入新记录(id=2)”。

  • 将原记录标记为已删除(Delete Mark)。
  • 插入新记录。
  • 这两步都会产生对应的Undo Log。

回滚原理

当执行rollback时,InnoDB会沿着Undo Log的版本链逆向操作。例如:

  1. 识别出最后操作的Undo Log。
  2. 如果是Update,还原旧值。
  3. 如果是Delete,重新插入原记录。
  4. 如果是Insert,直接删除记录。

Binlog简介

除了InnoDB层的日志,MySQL Server层还有Binlog(Binary Log)。它记录了所有修改数据的SQL语句(逻辑日志),与具体的存储引擎无关。

  • 用途:主从复制(Replication)、数据备份与恢复。
  • 查看方法:show variables like '%log_bin%';
  • 读取工具:mysqlbinlog -v "filename"
  • 清理命令:PURGE BINARY LOGS TO 'filename'; 或 PURGE BINARY LOGS BEFORE 'time';

Binlog写入时机

为了防止一个大事务导致内存溢出,每个连接拥有独立的Binlog Cache。当事务提交时,整个事务的Binlog必须一次性写入磁盘文件中,因此Binlog无法分割。

Redo Log与Binlog的区别

  • 层级不同:Redo Log是InnoDB存储引擎层产生的物理日志;Binlog是Server层的逻辑日志。
  • 内容不同:Redo Log记录页级的修改细节;Binlog记录原始SQL语句。
  • 作用不同:Redo Log用于本地崩溃恢复;Binlog用于集群间数据同步。

两阶段提交(Two-Phase Commit, 2PC)

由于Redo Log和Binlog的写入时机不同(Redo在事务过程中可不断写入,Binlog仅在提交时写入),这可能导致逻辑不一致。例如:事务更新了数据,Redo Log已写完,但在写Binlog时发生宕机。重启后,InnoDB根据Redo Log恢复数据,但该次更新未被记录在Binlog中,导致主库与从库数据不一致。

如何解决不一致?

InnoDB使用了两阶段提交方案,将Redo Log分为两个状态:prepare 和 commit。

  1. Prepare阶段:写入Redo Log,状态设为PREPARE。此时日志已持久化,但尚未正式生效,也不允许其他事务完全依赖此日志恢复。
  2. Binlog阶段:将同一事务的操作写入Binlog。
  3. Commit阶段:将Redo Log的状态改为COMMIT,表示事务完整结束。

异常场景分析

场景A:写完Redo(PREPARE),写Binlog前宕机

恢复时,InnoDB发现Redo Log处于PREPARE状态且找不到对应的Binlog(因为没写完)。为了保证一致性,InnoDB会选择回滚该事务。

场景B:写完Binlog,准备改Redo(COMMIT)时宕机

恢复时,InnoDB发现Redo Log处于PREPARE状态,但能查找到完整的Binlog。这说明事务实际上是成功的,只是最后的标记没写完。InnoDB会选择提交该事务。

总结两阶段提交的保护机制

  • 写Binlog失败:由于Redo是PREPARE且无Binlog匹配 -> 回滚,保证数据不发生无效更新。
  • Redo COMMIT失败:由于Redo是PREPARE但有完整Binlog -> 提交,防止有效数据丢失。

以上就是MySQL日志专项之Redo Log和Undo Log介绍的详细内容,更多关于MySQL redo log与undo log的资料请关注本站其它相关文章!

相关标签:

免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。

Python 相关产品和应用

全部下载
Selenium

Selenium

4.51.0 · Windows

用于浏览器自动化和 Web 测试的 Python 工具。

scikit-learn

scikit-learn

1.9.1 · Windows

常用 Python 机器学习算法与模型评估工具库。

Black

Black

26.10.1 · Windows

强调一致性的 Python 自动代码格式化工具。

Ruff

Ruff

0.17.1 · macOS

由 Rust 编写的高速 Python 代码检查和格式化工具。

pytest

pytest

9.1.1 · Windows

简洁而强大的 Python 自动化测试框架。

FastAPI

FastAPI

0.146.0 · Windows

高性能 Python API 框架,支持类型提示和自动接口文档。

Flask

Flask

3.1.3 · Windows

轻量灵活的 Python Web 应用框架。

Django

Django

6.1.2 · Windows

成熟的 Python Web 框架,适合构建内容站点和业务系统。

Spyder

Spyder

6.1.7 · Windows

面向科学计算与数据分析的 Python 集成开发环境。

SciPy

SciPy

1.18.1 · Windows

面向科学、工程和技术计算的 Python 算法库。