MySQL 三大日志系统深度解析:Binlog、Redo Log、Undo Log

一、概述

MySQL 的日志系统是数据库可靠性与一致性的基石。三大日志各司其职,共同保障事务的 ACID 特性:

日志类型 核心作用 保障特性 所属层级
Redo Log 崩溃恢复、持久化保证 持久性 (Durability) InnoDB 存储引擎层
Undo Log 事务回滚、多版本并发控制 原子性 (Atomicity)、隔离性 (Isolation) InnoDB 存储引擎层
Binlog 主从复制、数据归档与恢复 一致性 (Consistency) MySQL Server 层

二、Redo Log(重做日志)

2.1 核心原理

Redo Log 是 InnoDB 存储引擎特有的物理日志 ,采用 WAL(Write-Ahead Logging,预写日志) 机制。

WAL 核心思想:先写日志,再写磁盘。当数据修改时,先将修改记录到 Redo Log,事务即可提交成功,数据页可以稍后异步刷盘。

物理日志格式:记录的是"在某个数据页上做了什么修改",例如:

复制代码
对 表空间X 的数据页Y 的偏移量Z 处写入数据A

2.2 为什么需要 Redo Log?

直接刷盘数据页存在两大问题:

  1. 性能问题 :数据页大小为 16KB,可能只修改了几字节却要刷整个页,且是随机写(数据页在磁盘上位置分散)
  2. 可靠性问题:Buffer Pool 基于内存,断电后脏页数据会丢失

Redo Log 的优势:

  • 记录内容精简(仅需几十字节:表空间号、数据页号、偏移量、更新值)
  • 顺序写性能远高于随机写
  • 事务提交时只需保证 Redo Log 持久化,无需等待脏页刷盘

2.3 存储结构与刷盘策略

存储结构:

  • 固定大小的循环文件(默认 ib_logfile0 和 ib_logfile1)
  • 写满后从头开始覆盖,仅保留未刷盘的脏页日志

刷盘策略 (由 innodb_flush_log_at_trx_commit 控制):

参数值 行为 安全性 性能
0 每秒写入磁盘一次 可能丢失 1 秒数据 最高
1 每次事务提交都 fsync 最安全(推荐生产环境) 较低
2 每次提交写入 OS 缓存,由 OS 决定刷盘时机 可能丢失部分数据 较高

生产环境建议 :设置为 1(双 1 配置之一),配合 sync_binlog=1 确保数据安全。

2.4 Crash-Safe 机制

当 MySQL 崩溃重启时,InnoDB 会扫描 Redo Log:

  • 已提交事务:重放(前滚)Redo Log,恢复未刷盘的数据修改
  • 未提交事务:结合 Undo Log 回滚

这就是 Crash-Safe(崩溃恢复) 能力,确保已提交事务的数据不丢失。


三、Undo Log(回滚日志)

3.1 核心原理

Undo Log 是 逻辑日志 ,记录的是事务修改之前的数据状态,用于实现事务回滚和 MVCC。

逻辑日志格式:记录反向操作

  • INSERT → 记录对应的 DELETE 信息
  • DELETE → 记录对应的 INSERT 信息
  • UPDATE → 记录修改前的旧值

3.2 两大核心作用

1. 事务回滚(保证原子性)

事务执行过程中出现错误或执行 ROLLBACK 时,MySQL 利用 Undo Log 将数据恢复到事务开始前的状态。

执行流程示例:

复制代码
START TRANSACTION;
DELETE FROM products WHERE id = 10;
-- 发现删错了
ROLLBACK;
  1. 执行 DELETE 前,先将 id=10 的完整记录写入 Undo Log
  2. 标记数据行为删除状态
  3. 执行 ROLLBACK 时,根据 Undo Log 恢复原始数据
2. MVCC(多版本并发控制)

Undo Log 是实现 MVCC 的关键因素之一 :

版本链机制:

  • 每行数据包含两个隐藏字段:

    • DB_TRX_ID:创建或最后修改该行的事务 ID

    • DB_ROLL_PTR:指向 Undo Log 的回滚指针

  • 多个事务对同一行数据的修改会形成 Undo Log 版本链

Read View + Undo Log:

  • 读已提交(RC):每次 SELECT 创建新的 Read View,读取最新已提交版本

  • 可重复读(RR):事务开始时创建 Read View 并复用,通过 Undo Log 版本链找到事务开始前的数据版本

3.3 生命周期与清理机制

Undo Log 管理流程 :

  1. 事务开始时,分配 Undo Log 空间(位于回滚段 Rollback Segment)
  2. 事务执行中,记录修改前的数据
  3. 事务提交后,Undo Log 不会立即删除(需继续为 MVCC 服务)
  4. Purge 线程定期检查不再被任何事务视图引用的 Undo Log 并回收

监控命令:

复制代码
SHOW ENGINE INNODB STATUS\G
-- 查看 "History list length",持续增长说明 Purge 跟不上

四、Binlog(二进制日志/归档日志)

4.1 核心原理

Binlog 是 MySQL Server 层实现的逻辑日志,记录所有引起数据变更的操作(DDL、DML),所有存储引擎都可使用。

4.2 主要作用

  1. 主从复制:主库将 Binlog 传输到从库,从库重放实现数据同步
  2. 数据恢复:基于时间点的恢复(Point-In-Time Recovery),全量备份 + Binlog 增量恢复
  3. 数据审计:追踪数据变更历史

4.3 三种记录格式

格式 记录内容 优点 缺点 适用场景
STATEMENT 原始 SQL 语句 日志量小 动态函数(如 NOW()、UUID())可能导致主从不一致 简单场景(已不推荐)
ROW 行数据修改前后的值 精确复制,无歧义 日志量大(批量更新产生大量记录) 生产环境推荐
MIXED 自动选择 STATEMENT 或 ROW 折中方案 切换逻辑复杂 过渡方案

生产建议 :使用 binlog_format=ROW,配合 sync_binlog=1。

4.4 与 Redo Log 的关键区别

特性 Redo Log Binlog
层级 InnoDB 存储引擎层 MySQL Server 层
日志类型 物理日志(页修改) 逻辑日志(SQL/行数据)
写入方式 循环写(固定大小,覆盖旧日志) 追加写(文件满后新建,保留历史)
用途 崩溃恢复(Crash Recovery) 主从复制、时间点恢复
保留内容 仅未刷盘的脏页日志 全量历史变更记录

五、两阶段提交(2PC):保证日志一致性

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

Redo Log 和 Binlog 的写入时机不同:

  • Redo Log 在事务执行过程中可不断写入
  • Binlog 仅在事务提交时写入

如果直接提交,可能出现两种不一致情况:

情况 1:先写 Redo 再写 Binlog

  • Redo 标记提交 → 崩溃 → Binlog 未写入
  • 主库数据已更新,但 Binlog 缺失,从库无法同步此事务

情况 2:先写 Binlog 再写 Redo

  • Binlog 写入 → 崩溃 → Redo 未标记提交
  • 主库回滚此事务,但从库已执行,导致主从不一致

5.2 两阶段提交流程

复制代码
-- 阶段 1:Prepare
写入 Redo Log,标记为 PREPARE 状态,记录 XID(事务 ID)

-- 阶段 2:Commit  
写入 Binlog
更新 Redo Log 为 COMMIT 状态

崩溃恢复判断逻辑 :

  • Redo 为 PREPARE 且 Binlog 存在对应 XID → 提交事务
  • Redo 为 PREPARE 但 Binlog 无对应 XID → 回滚事务

六、事务执行全流程

以 UPDATE 操作为例,展示三大日志的协作:

复制代码
┌─────────────────────────────────────────────────────────────┐
│  1. 开启事务                                                  │
│     └─► 分配 Rollback Segment,准备 Undo Log 空间              │
├─────────────────────────────────────────────────────────────┤
│  2. 执行 UPDATE                                               │
│     ├─► 记录修改前的旧值到 Undo Log(Buffer Pool 中的 Undo 页)│
│     ├─► 修改 Buffer Pool 中的数据页(标记为脏页)              │
│     └─► 将修改记录到 Redo Log Buffer                         │
├─────────────────────────────────────────────────────────────┤
│  3. 事务提交(两阶段提交)                                      │
│     ├─► 阶段 1:Redo Log PREPARE(刷盘)                     │
│     ├─► 写入 Binlog(刷盘)                                   │
│     └─► 阶段 2:Redo Log COMMIT                              │
├─────────────────────────────────────────────────────────────┤
│  4. 后台异步刷脏页(Checkpoint)                               │
│     └─► 脏页刷盘后,对应 Redo Log 空间可被重用                 │
├─────────────────────────────────────────────────────────────┤
│  5. Purge 线程清理 Undo Log                                   │
│     └─► 当无事务需要旧版本数据时,清理过期 Undo Log            │
└─────────────────────────────────────────────────────────────┘

七、总结

日志 核心职责 关键机制 生产配置建议
Redo Log 保证已提交事务不丢失 WAL、顺序写、循环覆盖 innodb_flush_log_at_trx_commit=1
Undo Log 支持回滚和 MVCC 版本链、Purge 清理 监控 History list length,避免膨胀
Binlog 主从复制与数据恢复 两阶段提交、ROW 格式 binlog_format=ROW,sync_binlog=1

三大日志协同保障 ACID:

  • 原子性(A):Undo Log 实现回滚
  • 一致性(C):Redo + Undo + Binlog 共同保证崩溃后的一致性状态
  • 隔离性(I):Undo Log 支持 MVCC 实现非锁定读
  • 持久性(D):Redo Log 保证已提交事务不丢失

掌握这三大日志的底层原理,是构建高可用、高性能 MySQL 数据库架构的基础

相关推荐
IT枫斗者枫哥2 小时前
MyBatis一对多分页:LIMIT 20,为什么凑不齐20个订单?
java·数据库
Flynt2 小时前
"MySQL搜不动就上ES"?我先在50万行数据上测了它自带的ngram全文索引
mysql·elasticsearch·搜索引擎
Y002 小时前
PostgreSQL 的锁:为什么你的 ALTER TABLE 会卡住,以及怎么查
数据库·postgresql
imDwAaY3 小时前
Redo Log 和 Binlog 为什么需要两阶段提交?
后端·mysql
灰原喜欢柯南3 小时前
OceanBase 运维管理知识点——OCP 监控、诊断与变更控制
数据库·oceanbase
码农-0043 小时前
Springboot 集成 Ehcache操作数据库显示SQL语句设置
数据库·spring boot·sql
仍然.3 小时前
Redis---事务
数据库·redis
oradh3 小时前
Oracle 执行计划的阅读方法(二叉树结构来理解和阅读)
数据库·oracle·执行计划的阅读方法
SelectDB3 小时前
Doris 向量检索上线踩坑记录:七个排查现场与可直接复制的命令
大数据·数据库·数据分析
数据库小学妹3 小时前
MySQL深分页优化:LIMIT大偏移的根因分析与五种解法对比
数据库·mysql·性能优化