MySQL 的 InnoDB 存储引擎中,redo log、undo log 和 binlog 是保障数据一致性、持久性和可恢复性的三大核心组件。它们各自承担不同的职责,但在事务执行过程中紧密协作,共同构建了一个高可靠、高性能的数据库系统。本文将深入解析这三种日志的概念、作用及其协同工作机制。
一、三大日志的基本概念
1. redo log(重做日志)
redo log 是 InnoDB 引擎层特有的物理日志,记录的是数据页的物理修改,例如"在第123号数据页的偏移45字节处,将值从0x01修改为0x0A"。它的核心职责是保障事务的持久性(Durability),即确保已提交事务的修改不会因数据库崩溃而丢失。redo log 采用循环写入方式,固定大小,写满后覆盖最早的日志。当数据库异常重启时,InnoDB 通过重放 redo log 中未刷盘的脏页修改,实现崩溃恢复。
2. undo log(回滚日志)
undo log 是 InnoDB 引擎层的逻辑日志,记录的是数据修改前的旧值,用于支持事务的回滚操作和 MVCC(多版本并发控制)。例如,执行 UPDATE user SET age = 25 WHERE id = 1(原值为20)时,undo log 会记录"将 age 从 25 改回 20"的操作。undo log 的核心作用有两个:一是保障事务的原子性(Atomicity),当事务执行失败或显式执行 ROLLBACK 时,系统通过 undo log 将数据恢复到修改前的状态;二是支持 MVCC,通过维护数据的版本链,使不同事务能够读取到各自隔离级别下的数据快照,实现非锁定读。
3. binlog(归档日志)
binlog 是 MySQL Server 层的逻辑日志,记录的是 SQL 语句或行变更的逻辑操作,例如 UPDATE user SET age = 25 WHERE id = 1。它适用于所有存储引擎,采用追加写入方式,文件写满后新建下一个文件。binlog 的主要用途有两个:一是主从复制,主库将 binlog 发送给从库,从库重放以实现数据同步;二是数据恢复,通过 mysqlbinlog 工具可以恢复指定时间点的数据。
二、三大日志的职责对比
| 日志类型 | 所属层级 | 日志类型 | 核心职责 | 写入方式 | 适用引擎 |
|---|---|---|---|---|---|
| redo log | InnoDB 引擎层 | 物理日志 | 崩溃恢复(持久性) | 循环写 | 仅 InnoDB |
| undo log | InnoDB 引擎层 | 逻辑日志 | 事务回滚 + MVCC(原子性) | 顺序写 | 仅 InnoDB |
| binlog | MySQL Server 层 | 逻辑日志 | 主从复制 + 数据归档 | 追加写 | 所有引擎 |
三、三大日志的协同工作流程
以执行 UPDATE user SET age = 25 WHERE id = 1(原值为20)为例,三大日志的协同工作流程如下:
1. 事务开始
事务启动时,InnoDB 为该事务分配一个唯一的事务 ID,并初始化事务上下文。
2. 写 undo log
在修改数据之前,InnoDB 首先将修改前的旧值写入 undo log。例如,记录"将 age 从 25 改回 20"。这一步是事务回滚和 MVCC 的基础。
3. 修改 Buffer Pool 中的数据页
在内存中的 Buffer Pool 里,将 id=1 的记录的 age 字段从 20 修改为 25。此时,该数据页成为"脏页"(与磁盘不一致)。
4. 写 redo log
InnoDB 将本次修改的物理信息写入 redo log buffer,并尽快刷入磁盘。redo log 记录的是"第123号页,偏移45字节,从0x01改为0x0A"这样的物理变更。
5. 事务提交
事务提交时,执行两阶段提交协议:首先将 redo log 标记为 prepare 状态;然后写入 binlog;最后将 redo log 标记为 commit 状态。
6. 后台异步刷脏页
事务提交后,脏页不会立即刷入磁盘,而是由后台的 page_cleaner 线程在合适时机(如系统空闲、脏页比例过高、redo log 快写满时)批量异步刷盘。
四、崩溃恢复场景分析
假设在事务提交过程中发生崩溃,三大日志如何协同恢复?
场景一:redo log 是 commit 状态
说明事务已完整提交,直接应用 redo log 中的修改,恢复数据。
场景二:redo log 是 prepare 状态,且能找到对应的完整 binlog
说明 binlog 已写入,事务应被提交。MySQL 会补写 redo log 的 commit 标记,并应用修改。
场景三:redo log 是 prepare 状态,但找不到对应的 binlog
说明 binlog 未写完,事务不完整。MySQL 会使用 undo log 回滚该事务,确保数据一致性。
五、MVCC 与 undo log 的关系
在可重复读(Repeatable Read)隔离级别下,事务 A 启动时,InnoDB 会为其生成一个 Read View。当事务 A 读取某行数据时,InnoDB 会沿着该行的版本链(由 undo log 维护)查找符合 Read View 可见性规则的版本。例如,事务 B 将 age 从 20 修改为 25,undo log 中保留了 age=20 的旧版本。事务 A 在读取时,若判断事务 B 的修改对其不可见,则会读取 undo log 中的旧版本,从而实现非锁定读。
六、总结
redo log、undo log 和 binlog 是 MySQL InnoDB 引擎的三大支柱。redo log 保障持久性,undo log 保障原子性并支持 MVCC,binlog 支持主从复制与数据归档。三者各司其职,又通过两阶段提交协议紧密协作,共同构建了一个高可靠、高性能、高一致性的数据库系统。理解这三种日志的协同机制,是深入掌握 MySQL 事务原理的关键。