深入剖析 MySQL 日志系统:Redo Log、Undo Log 与 Binlog 的协同工作原理


文章目录

  • [引言:为什么 MySQL 需要三种日志?](#引言:为什么 MySQL 需要三种日志?)
  • 一、要点速览
  • [二、Redo Log:崩溃恢复的基石](#二、Redo Log:崩溃恢复的基石)
    • [2.1 为什么需要 Redo Log?](#2.1 为什么需要 Redo Log?)
    • [2.2 Redo Log 的本质](#2.2 Redo Log 的本质)
    • [2.3 写入机制与刷盘策略](#2.3 写入机制与刷盘策略)
    • [2.4 Checkpoint 与恢复](#2.4 Checkpoint 与恢复)
  • [三、Undo Log:原子性与 MVCC 的幕后功臣](#三、Undo Log:原子性与 MVCC 的幕后功臣)
    • [3.1 事务回滚的保证](#3.1 事务回滚的保证)
    • [3.2 MVCC 的核心支撑](#3.2 MVCC 的核心支撑)
  • [四、Binlog:Server 层的全局日志](#四、Binlog:Server 层的全局日志)
    • [4.1 Binlog 的定位](#4.1 Binlog 的定位)
    • [4.2 三种格式对比](#4.2 三种格式对比)
    • [4.3 Binlog 的写入与刷盘](#4.3 Binlog 的写入与刷盘)
  • [五、两阶段提交:Redo Log 与 Binlog 的握手协议](#五、两阶段提交:Redo Log 与 Binlog 的握手协议)
    • [5.1 为什么需要两阶段提交?](#5.1 为什么需要两阶段提交?)
    • [5.2 两阶段提交流程](#5.2 两阶段提交流程)
    • [5.3 崩溃恢复时的判断规则](#5.3 崩溃恢复时的判断规则)
  • 七、常见误区澄清
  • 八、总结

引言:为什么 MySQL 需要三种日志?

作为一款成熟的关系型数据库,MySQL(特别是搭配 InnoDB 存储引擎后)需要在多个看似矛盾的目标之间取得平衡:性能与持久性、并发与一致性、单机恢复与主从复制。单一的日志机制无法同时满足这些需求。因此,MySQL 设计了三种职责分明、彼此协作的日志:Redo Log、Undo Log、Binlog。

理解它们的作用与交互方式,是掌握 MySQL 事务机制、崩溃恢复、MVCC 以及高可用架构的基础。本文将从三个日志的本质出发,逐步深入到两阶段提交协议和完整的协作流程,帮助读者建立起系统化的认知。


一、要点速览

日志类型 核心作用 归属层 关键特性
Redo Log 保证事务持久性,实现崩溃恢复 InnoDB 物理日志、循环写、WAL
Undo Log 保证事务原子性,支持 MVCC InnoDB 逻辑日志、版本链、Purge
Binlog 主从复制与时间点恢复 Server 层 逻辑/SQL日志、追加写、2PC

三者共同实现了 MySQL 的 WAL(Write-Ahead Logging) 架构,并借助两阶段提交保证跨日志的一致性。

二、Redo Log:崩溃恢复的基石

2.1 为什么需要 Redo Log?

如果没有 Redo Log,事务提交时需要立即将修改的数据页刷回磁盘。但数据页的写入是随机 I/O,性能极差。Redo Log 解决了这一矛盾:

  • 事务提交时,只写入顺序 I/O 的 Redo Log,后台异步再将数据页刷回磁盘。

这就是 WAL(Write-Ahead Logging) 的核心思想:日志先行,数据滞后。

2.2 Redo Log 的本质

  • 物理日志:记录"在某个表空间的某个数据页的某个偏移量处,写入什么值"。
  • 循环写:Redo Log 由固定大小的文件(如 ib_logfile0、ib_logfile1)组成,写满后覆盖最老的未刷盘日志(通过 Checkpoint 控制)。
  • 重放幂等:多次重放同一 Redo Log 结果相同,适合崩溃恢复。

2.3 写入机制与刷盘策略

Redo Log 并非每次直接写磁盘,而是经过三层结构:

  • Redo Log Buffer(内存)
  • OS Cache
  • 磁盘文件

关键参数 innodb_flush_log_at_trx_commit:

行为 持久性 性能
0 每秒刷一次,事务提交不刷 可能丢失1秒数据 最高
1 每次提交都刷盘(fsync) 最强 较低
2 只写入OS Cache,不保证落盘 操作系统崩溃可能丢失 较高

生产环境推荐 =1,保证 ACID 持久性。

2.4 Checkpoint 与恢复

  • Checkpoint:当 Redo Log 写满一定比例或手动触发时,将脏页刷回磁盘,并标记日志可覆盖。
  • 崩溃恢复:MySQL 重启后,从最后一次 Checkpoint 开始顺序重放 Redo Log,恢复所有已提交但未刷盘的事务。

三、Undo Log:原子性与 MVCC 的幕后功臣

3.1 事务回滚的保证

Undo Log 的核心职责之一是事务原子性:

  • 当事务执行中发生错误或被显式回滚时,利用 Undo Log 将数据恢复为修改前的状态。

与 Redo Log 不同,Undo Log 记录的是逻辑日志,例如:

  • "将 id=10 的 name 字段从 'A' 改回 'B'"
  • "删除之前插入的某条记录"

3.2 MVCC 的核心支撑

Undo Log 另一个至关重要的角色是多版本并发控制(MVCC)。

  • 每次更新操作会生成一个新版本的数据行,同时旧版本保留在 Undo Log 中。
  • 多个旧版本通过指针串联形成版本链。
  • 不同隔离级别下的 Read View 决定事务能看到哪个版本。

典型场景:

  • 可重复读(RR)下,一个事务内的多次查询看到的是同一快照(由最早的 Read View 决定),不受其他事务提交影响。
  • 读已提交(RC)下,每次查询生成新的 Read View,能看到已提交的最新数据。

3.3 Purge 线程:版本清理

Undo Log 不能无限增长。当满足以下条件时,Purge 线程会异步清理不再需要的 Undo 版本:

  • 该版本在所有活跃事务的 Read View 中都不可见
  • 没有更老的事务需要访问它

如果存在长事务,会导致 Undo Log 堆积,影响性能甚至磁盘空间。

四、Binlog:Server 层的全局日志

4.1 Binlog 的定位

与 Redo / Undo Log 不同,Binlog 属于 MySQL Server 层,所有存储引擎(不仅是 InnoDB)都会产生它。

核心用途:

  • 主从复制:从库重放 Binlog 实现数据同步。
  • 基于时间点的恢复:利用全量备份 + Binlog 恢复到任意时刻。

4.2 三种格式对比

格式 记录内容 优点 缺点
STATEMENT 原始SQL语句 日志量小 非确定性函数、存储过程可能导致主从不一致
ROW 每行数据变更的前后镜像 最安全、准确 日志量大,大事务可能影响性能
MIXED 默认STATEMENT,不安全时自动切换ROW 平衡 配置复杂,行为不易预测

生产环境一般建议使用 ROW 格式,尤其在有主从复制的场景下。

4.3 Binlog 的写入与刷盘

通过参数 sync_binlog 控制:

  • =0:由操作系统决定何时刷盘,性能最好但可能丢日志。
  • =1:每次事务提交都刷盘,最安全。
  • =N:每 N 个事务刷一次。

主从一致性要求高时,通常设置为 1。

五、两阶段提交:Redo Log 与 Binlog 的握手协议

5.1 为什么需要两阶段提交?

假设没有 2PC:

  • 先写 Binlog,再写 Redo Log:写完 Binlog 后崩溃,Redo Log 中无该事务,主从不一致。
  • 先写 Redo Log,再写 Binlog:写完 Redo Log 后崩溃,Binlog 无该事务,从库丢失数据。

核心矛盾:Redo Log 负责崩溃恢复,Binlog 负责复制与恢复,两者必须逻辑一致。

5.2 两阶段提交流程

  1. Prepare 阶段
    • 事务修改数据,生成 Redo Log 和 Undo Log。
    • Redo Log 写入磁盘并标记为 Prepare 状态。
  2. Commit 阶段
    • 写入 Binlog 并刷盘。
    • 将 Redo Log 状态从 Prepare 改为 Commit。

5.3 崩溃恢复时的判断规则

  • 若 Redo Log 为 Commit → 提交事务。
  • 若 Redo Log 为 Prepare:
    • 检查 Binlog 是否完整(包含该事务) → 提交
    • 否则 → 回滚

这套机制保证了:任何一个日志中可见的事务,另一个日志中也必然存在。

六、三种日志的协作全景图

以下是一个 UPDATE 语句在执行过程中,三种日志的完整协作流程:
后台异步任务
事务提交阶段
事务执行阶段
崩溃恢复场景
Redo Log = Commit
Redo Log = Prepare


MySQL 崩溃重启
扫描 Redo Log
提交事务

重放 Redo Log
检查 Binlog

是否包含该事务
提交事务
回滚事务

利用 Undo Log
开始事务
执行 UPDATE 语句
生成 Undo Log

记录旧值
修改 Buffer Pool 中的脏页
生成 Redo Log

状态 = Prepare
将 Redo Log 写入磁盘

顺序 I/O
写入 Binlog 并刷盘
两阶段提交判断
将 Redo Log 状态改为 Commit
事务提交成功
后台线程异步将脏页刷回磁盘

随机 I/O
Purge 线程清理

不再需要的 Undo Log

流程图解读

  1. 事务执行阶段:Undo Log 先记录旧值(用于回滚和 MVCC),然后修改内存中的脏页,同时生成 Prepare 状态的 Redo Log 并刷盘(顺序 I/O,性能高)。
  2. 事务提交阶段:先写 Binlog 并刷盘,再将 Redo Log 从 Prepare 改为 Commit。这是两阶段提交的核心,保证 Redo Log 与 Binlog 的一致性。
  3. 后台异步任务:事务提交后,后台线程会择机将脏页刷回磁盘(随机 I/O),Purge 线程也会清理无用的 Undo Log 版本。
  4. 崩溃恢复场景:MySQL 重启后根据 Redo Log 状态和 Binlog 完整性决定事务是提交还是回滚。

七、常见误区澄清

误区 正解
"Redo Log 就是 WAL" Redo Log 是 WAL 的具体实现,WAL 是一种思想。
"Binlog 也能做崩溃恢复" Binlog 只能做基于时间点的恢复,不能保证事务原子性恢复。
"Undo Log 只在回滚时有用" MVCC 下读请求也需要 Undo Log 来构造旧版本。
"两阶段提交影响性能严重" 顺序刷盘开销可接受,且是保证一致性的必要代价。

八、总结

用一句话概括三种日志的分工:

  • Redo Log:不怕崩溃,保证你提交的数据不丢。
  • Undo Log:不怕回滚,保证你能回到从前;同时也让你读到一致的快照。
  • Binlog:不怕主从同步和误删,保证你能重建和恢复。

三者合在一起,才让 MySQL 成为一个既高性能又高可靠、既支持并发又支持复制的成熟数据库系统。

掌握这些日志的原理,不仅仅是应对面试题,更是你日后进行性能调优、故障排查、架构设计(如分库分表、主从延迟分析)的底层能力支撑。


相关推荐
NineData1 天前
NineData 智能数据管理平台新功能发布|2026 年 3 月
数据库·oracle·架构·dba·ninedata·数据复制·数据迁移工具
小陈工1 天前
2026年4月7日技术资讯洞察:下一代数据库融合、AI基础设施竞赛与异步编程实战
开发语言·前端·数据库·人工智能·python
❀͜͡傀儡师1 天前
k8s部署的Nexus 3 数据库损坏恢复指南:从删除损坏数据库到完整数据重建
数据库·kubernetes·nexus3
StackNoOverflow1 天前
Spring Security权限控制框架详解
java·数据库·sql
不愿透露姓名的大鹏1 天前
Oracle归档日志爆满急救指南
linux·数据库·oracle·dba
a里啊里啊1 天前
Redis面试题记录
数据库·redis·缓存
数据知道1 天前
claw-code 源码分析:OmX `$team` / `$ralph`——把 AI 辅助开发从偶发灵感变成可重复流水线
数据库·人工智能·mysql·ai·claude code·claw code
__土块__1 天前
大厂后端一面模拟:从线程安全到分布式缓存的连环追问
jvm·redis·mysql·spring·java面试·concurrenthashmap·大厂后端
麦聪聊数据1 天前
企业数据流通与敏捷API交付实战(六):内部API门户与自助分发机制
数据库·低代码·restful·etl
做个文艺程序员1 天前
深入 MySQL 内核:MVCC、Buffer Pool 与高并发场景下的极限调优
数据库·mysql·adb