Mysql

关注公众号 jb51net

关闭
首页 > 数据库 > Mysql > MySQL核心日志

深入详解三大MySQL核心日志:redo log、undo log和bin log

作者:花生了什么事o

本文介绍 MySQL 三种核心日志——redo log、undo log、binlog,分别解释它们的作用、记录格式和适用场景,并通过一条UPDATE 语句的完整执行流程串联三者的协作关系,希望对大家有所帮助

三种日志分别是什么

先给一个全景概览,后面逐一展开:

日志所属层核心作用
redo logInnoDB 存储引擎层崩溃恢复,保证事务持久性(Durability)
undo logInnoDB 存储引擎层事务回滚,支持 MVCC
binlogMySQL Server 层主从复制,数据备份与恢复

一个关键区别:redo log 和 undo log 是 InnoDB 引擎独有的,binlog 是 MySQL Server 层的功能,和具体存储引擎无关。

打个比方。把 MySQL 想象成一家公司:

redo log:保证崩溃不丢数据

为什么需要redo log

InnoDB 更新数据时,不会每次都直接写磁盘。它会先把数据页从磁盘读到内存(Buffer Pool),在内存中修改,然后由后台线程择机把脏页刷回磁盘。这个机制叫 WAL(Write-Ahead Logging)——先写日志,再写磁盘。

问题来了:如果脏页还没刷回磁盘就崩溃了,修改不就丢了吗?

redo log 解决的就是这个问题。更新操作在修改内存数据页的同时,会把"对某个数据页做了什么修改"记录到 redo log 里。即使崩溃时脏页没刷盘,重启后 InnoDB 会读取 redo log,把未完成的修改重新应用到数据页上。

redo log 记录的是"物理修改"——某个表空间的某个页的某个偏移量,写入了什么数据。 这种日志格式叫物理日志,恢复速度极快,因为它不需要重新执行 SQL 语句,直接把字节级的修改写回去就行。

redo log 的结构

redo log 不是一个无限大的文件,而是固定大小的循环写入结构。它由一组文件组成,比如默认的 ib_logfile0ib_logfile1

write pos 和 checkpoint 之间的区域是"待处理"的 redo log。如果 write pos 追上了 checkpoint,说明 redo log 满了,此时必须暂停更新,先推进 checkpoint(把脏页刷盘),腾出空间。

这就是为什么 redo log 是固定大小的——它不需要永久保存,数据页一旦安全落盘,对应的 redo log 就可以被覆盖。

undo log:事务回滚与MVCC的基石

两个核心职责

undo log 承担了两个看似不同但紧密相关的职责:

职责一:事务回滚。 事务执行到一半,执行了 UPDATE user SET name = '李四' WHERE id = 1,但还没 COMMIT。此时如果执行 ROLLBACK,InnoDB 需要知道"改之前 name 是什么"——这个信息就存在 undo log 里。

undo log 记录的是逻辑操作的逆操作。如果是 INSERT,undo log 就记一条 DELETE;如果是 UPDATE,undo log 就记旧值。回滚时,执行 undo log 里的逆操作,数据就恢复了。

职责二:支持 MVCC。 这是 undo log 更重要的作用。在之前的 MVCC 文章里我们讲过,InnoDB 的每行记录有隐藏列 DB_TRX_ID(最后修改的事务ID)和 DB_ROLL_PTR(回滚指针)。每次 UPDATE 时,旧版本数据会被写入 undo log,DB_ROLL_PTR 指向它。多次更新后,一条记录就形成了一条版本链。

其他事务做快照读时,沿着版本链找到对自己可见的版本,读不加锁,并发性能直接拉满。

undo log 和 redo log 的区别

对比维度redo logundo log
记录内容物理修改(页+偏移+数据)逻辑逆操作(旧值)
作用崩溃恢复事务回滚 + MVCC
是否可清理数据页刷盘后可覆盖没有事务引用后由 purge 线程清理
存储位置系统表空间或独立文件undo 表空间

一个容易混淆的点:undo log 也需要 redo log 的保护。也就是说,写 undo log 的操作本身也会产生 redo log。因为 undo log 也是写在磁盘页上的,崩溃恢复时需要先把 undo log 页恢复好,才能用它来回滚未提交的事务。

示例场景

-- 事务执行:UPDATE users SET balance = 100 WHERE id = 1;
-- Undo Log 会记录旧值(如 balance = 50),用于回滚或 MVCC 读取。

binlog:Server层的归档日志

binlog 的作用

binlog 是 MySQL Server 层维护的日志,记录了所有修改数据的 SQL 语句(或行变更)。它的用途和引擎层的日志完全不同:

  1. 主从复制:主库把 binlog 发送给从库,从库重放 binlog,实现数据同步
  2. 数据恢复:通过 mysqlbinlog 工具,可以将数据库恢复到某个时间点(Point-in-Time Recovery)

binlog 的三种格式

格式记录内容优点缺点
STATEMENTSQL 语句原文日志量小某些函数(NOW()、UUID())主从不一致
ROW每行数据的变更前后值精确,主从一致日志量大
MIXED自动选择 STATEMENT 或 ROW折中行为不透明

生产环境推荐 ROW 格式。虽然日志量大,但数据一致性有保障,而且 ROW 格式的 binlog 也是基于时间点恢复的最可靠选择。

binlog 和 redo log 的关键区别

对比维度redo logbinlog
所属层InnoDB 引擎层MySQL Server 层
记录格式物理日志(页修改)逻辑日志(SQL/行变更)
写入方式循环写,空间固定追加写,文件用完切换新文件
用途崩溃恢复主从复制、数据恢复
是否所有引擎都有否,InnoDB 独有是,所有引擎通用

redo log 是"短命"的——数据安全落盘后就可以被覆盖。binlog 是"长寿"的——它会被永久保留,直到你手动清理。 这也是为什么 binlog 可以用来做时间点恢复,而 redo log 不行。

示例场景

-- 主库执行:INSERT INTO orders VALUES (...);
-- Bin Log 记录该操作,从库读取并重放,实现数据同步。

一条UPDATE语句的完整日志流程

现在把三种日志串起来,看一条 UPDATE user SET name = '李四' WHERE id = 1 的完整执行过程:

执行器
  │
  ├── 1. 从磁盘读取 id=1 的数据页到 Buffer Pool(如果不在内存中)
  │
  ├── 2. 写 undo log:记录旧值 name='张三'
  │       (用于事务回滚和 MVCC 版本链)
  │
  ├── 3. 更新 Buffer Pool 中的数据页:name 从 '张三' 改为 '李四'
  │
  ├── 4. 写 redo log(prepare 状态)
  │       (记录对数据页的物理修改)
  │
  ├── 5. 写 binlog
  │       (记录 SQL 语句或行变更)
  │
  └── 6. 提交事务,redo log 标记为 commit 状态

注意第 4 步和第 6 步:redo log 在事务提交前就写入了,但要经过两个阶段——先 prepare,再 commit。这就是两阶段提交。

两阶段提交:redo log和binlog的协调机制

为什么需要两阶段提交

redo log 和 binlog 是两个独立的日志系统,写入时机不同。如果先写 redo log 再写 binlog,或者反过来,在两者之间崩溃就会导致数据不一致。

场景一:先写 redo log,后写 binlog,中间崩溃

场景二:先写 binlog,后写 redo log,中间崩溃

两阶段提交把这两个日志的写入变成一个原子操作。

两阶段提交的流程

事务执行中
    │
    ├── 1. redo log 写入,标记为 prepare 状态
    │
    ├── 2. binlog 写入
    │
    └── 3. redo log 标记为 commit 状态

崩溃恢复时的判断逻辑:

崩溃时机redo log 状态binlog 是否存在恢复动作
步骤 1 之前崩溃事务丢失,无需处理
步骤 1 和 2 之间崩溃prepare回滚事务(binlog 不存在,说明事务未完成)
步骤 2 和 3 之间崩溃prepare提交事务(binlog 已存在,说明事务已生效)
步骤 3 之后崩溃commit正常恢复

核心判断依据:redo log 处于 prepare 状态时,检查 binlog 是否完整写入。如果 binlog 完整,就提交;不完整,就回滚。 这样即使中间崩溃,主从数据也保持一致。

三种日志对比

最后把三种日志放在一起做一次完整对比:

维度redo logundo logbinlog
所属层InnoDBInnoDBServer
记录格式物理日志逻辑日志逻辑日志
核心作用崩溃恢复(持久性)回滚 + MVCC(原子性 + 隔离性)复制 + 备份
写入方式循环写按需写入 undo 表空间追加写
生命周期数据页刷盘后可覆盖无事务引用后由 purge 清理永久保留(手动清理)
是否可关闭不可不可可以关闭(不推荐)

对应到事务的 ACID 特性:

小结

MySQL 的三种日志各有分工:redo log 保证崩溃恢复,undo log 支撑事务回滚和 MVCC,binlog 负责主从复制和数据归档。它们通过两阶段提交机制协调工作,确保即使在崩溃场景下,数据也能保持一致。

从设计哲学上看,这种分层日志架构体现了一个基本原则:不同的问题用不同的机制解决,然后用协调机制保证它们的一致性。 redo log 解决"写入性能"问题(WAL 让随机写变顺序写),undo log 解决"并发读写"问题(MVCC 让读写不阻塞),binlog 解决"数据分发"问题(复制和恢复)。三者各司其职,组合在一起,才构成了 MySQL 可靠运行的基石。

到此这篇关于深入详解三大MySQL核心日志:redo log、undo log和bin log的文章就介绍到这了,更多相关MySQL核心日志内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文