MySql Redo Log、Undo Log、Binlog 的职责与配合

一、三种日志的职责对比

Redo Log:重做日志
保证持久性

  • 所属:InnoDB 存储引擎
  • 作用:记录数据页发生的修改,用于崩溃恢复。
  • 核心问题:事务提交后,即使数据页还没写入磁盘,MySQL 崩溃了,如何恢复已提交的数据?

Undo Log:回滚日志
保证原子性,支持 MVCC

  • 所属:InnoDB 存储引擎
  • 作用:保存修改前的旧版本信息,支持事务回滚。
  • 核心问题:事务执行到一半失败了,如何撤销已经完成的修改?其他事务又如何读取旧版本数据?

Binlog:二进制日志
主从复制、数据恢复

  • 所属:MySQL Server 层
  • 作用:记录数据库的逻辑变更或相关事件,具体取决于日志格式。
  • 核心问题:主库的数据如何同步到从库?如何利用历史日志恢复到某个时间点?

一句话记忆:

  • Redo Log:崩溃后把已提交的修改恢复出来。
  • Undo Log:事务回滚时撤销修改,并为 MVCC 提供历史版本。
  • Binlog:记录数据库变更,供主从复制和时间点恢复使用。
    二、为什么需要三种日志?
    假设有一张账户表:
    CREATE TABLE account (
    id BIGINT PRIMARY KEY,
    balance DECIMAL(10, 2)
    ) ENGINE = InnoDB;

UPDATE account
SET balance = 900
WHERE id = 1;

原来的余额是 1000 元,现在修改为 900 元。

执行这条 SQL 时,三种日志分别承担不同的任务。
日志 记录的核心信息 用途
Undo Log 修改前余额为 1000 回滚时恢复旧值;支持一致性读
Redo Log 数据页需要体现余额变为 900 的修改 崩溃后重做已提交的修改
Binlog 这次数据变更对应的事件 将变更同步到从库;用于恢复
注意:这里为了便于理解,使用了简化后的逻辑描述。实际日志记录不一定是这样一条直观的文本,Redo Log 主要记录物理层面的页修改信息,Binlog 则根据配置采用不同的记录格式。
三、三种日志如何配合工作?
这是最重要的部分。我们分成事务执行、事务提交、崩溃恢复三个阶段来理解。

  1. 事务执行阶段
    假设账户余额从 1000 修改为 900:
    BEGIN;

UPDATE account
SET balance = 900
WHERE id = 1;

COMMIT;

大致流程如下:
执行 UPDATE

修改 InnoDB Buffer Pool 中的数据页

生成 Undo Log

保存旧版本信息,支持回滚和 MVCC

生成 Redo Log

记录数据页修改所需的重做信息

此时数据页不一定已经写入磁盘,Redo Log 也可能仍处于未提交状态。

这里需要注意两个细节:

  • Undo Log 本身也是由 InnoDB 管理的持久化数据,修改 Undo 页时也会涉及 Redo Log 保护。
  • Redo Log 采用预写日志(WAL)机制:通常先确保相关日志达到要求的持久化状态,再允许脏数据页稍后刷盘,而不是每次 UPDATE 都直接将数据页写入磁盘。
  1. COMMIT 阶段:两阶段提交(2PC)
    为什么 MySQL 需要两阶段提交?

因为 InnoDB 的 Redo Log 和 Server 层的 Binlog 是两套不同的日志系统。如果两者状态不一致,就可能造成数据恢复或主从复制不一致。

典型的提交顺序是:
1

Redo Log Prepare

InnoDB 将事务标记为准备提交状态,写入对应的 Redo Log 信息。

2

写入 Binlog

Server 层写入该事务对应的 Binlog,并根据配置决定何时同步到磁盘。

3

Redo Log Commit

InnoDB 将事务标记为提交完成。

这就是经典的 Prepare → Binlog → Commit 流程。

它不是说数据页必须在第三步写入磁盘,而是协调两套日志对事务提交状态的认定。
3. 如果 MySQL 在不同阶段崩溃,会发生什么?
崩溃位置 恢复时的处理
事务提交前 未提交事务需要回滚
Redo 已 Prepare,Binlog 尚未完整写入 通常判定事务未完成,执行回滚
Binlog 已写入,Redo 仍处于 Prepare 恢复时检查 Binlog 中对应事务是否存在且有效;满足提交条件则提交,否则回滚
Redo 已 Commit 恢复已提交事务的修改,即使数据页尚未刷盘
实际恢复还会考虑日志是否完整、事务标识是否匹配,以及相关持久化配置。这里的关键是:不能仅仅因为 Redo Log 里有修改记录,就认定事务已经提交。

这也是为什么 MySQL 需要协调 Redo Log 和 Binlog,而不是只保留其中一个。
四、Undo Log 如何实现事务回滚和 MVCC?

  1. 事务回滚
    例如:
    BEGIN;

UPDATE account SET balance = 900 WHERE id = 1;

-- 业务执行失败
ROLLBACK;

假设原余额为 1000,执行 UPDATE 后,InnoDB 已经产生了相关修改和 Undo Log。

执行 ROLLBACK 时,InnoDB 利用 Undo Log 中的旧版本信息撤销本次事务的修改,使余额恢复为 1000。

注意:回滚不等于删除所有日志。 Undo Log 记录的是撤销修改所需的信息,Redo Log 还负责保护包括相关撤销操作在内的持久化修改。
2. MVCC 如何利用 Undo Log?
假设事务 A 修改余额,而事务 B 进行普通的一致性读。
旧版本
balance = 1000
通过 Undo Log 保存的历史版本信息访问

当前版本
balance = 900
当前数据页中的记录版本

假设事务 A 将余额从 1000 改为 900,但尚未提交:

  • 事务 A 自己可以看到自己的修改。
  • 事务 B 使用普通 SELECT 时,在符合其 Read View 可见性规则的情况下,可以通过 Undo Log 读取余额为 1000 的旧版本。
  • 事务 A 提交后,事务 B 能否看到 900,取决于事务隔离级别、Read View 创建时机以及当前查询是否使用新的 Read View。
    所以,Undo Log 不只是为了 ROLLBACK,还为 InnoDB 的 MVCC 提供了历史版本链。

旧版本不会立即删除;当没有活跃事务再需要相关历史版本时,InnoDB 才能在后续清理过程中回收相应的 Undo 信息。
五、Redo Log 和 Binlog 的区别再深入一点
对比项 Redo Log Binlog
所属层级 InnoDB 引擎层 MySQL Server 层
主要用途 崩溃恢复 主从复制、时间点恢复
记录特点 以物理页修改相关信息为主 支持 Statement、Row、Mixed 格式
生命周期 固定容量的循环使用机制 按文件滚动,旧文件可按策略清理
是否支持非 InnoDB 引擎 不负责其他引擎的数据恢复 可以记录其他存储引擎涉及的数据库变更
核心价值 已提交修改的持久性 数据变更的可复制性与可恢复性
再补充两个容易考到的知识点:

  • Redo Log 通常采用循环写入机制,但不能简单理解为所有日志都能随意覆盖;检查点和未完成的恢复需求会限制可覆盖范围。
  • Binlog 可以配合全量备份,通过重放备份之后的日志,将数据库恢复到指定时间点。
    六、生产环境还需要了解的持久化参数
    参数 作用
    innodb_flush_log_at_trx_commit 控制 InnoDB Redo Log 的写入与刷盘策略
    sync_binlog 控制 Binlog 同步到磁盘的频率
    binlog_format 控制 Binlog 的记录格式,常见为 ROW
    binlog_expire_logs_seconds 控制 Binlog 的过期清理时间
    对于强调事务持久性和主从复制可靠性的场景,常见配置是:
    innodb_flush_log_at_trx_commit = 1
    sync_binlog = 1
    binlog_format = ROW

这通常意味着每次事务提交时,Redo Log 和 Binlog 都会执行相应的持久化操作;具体还取决于 MySQL 版本、操作系统、存储设备及相关配置。它会带来一定的 I/O 开销,但有助于降低崩溃导致的事务丢失风险。

posted @ 2026-10-20 14:37  程序小小猿  阅读(1)  评论(0)    收藏  举报