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_logfile0ib_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=ROWsync_binlog=1

三大日志协同保障 ACID

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

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

相关推荐
逃逸线LOF2 小时前
数据源 C3PO与Druid
数据库·oracle
m0_569881472 小时前
使用Python进行网络设备自动配置
jvm·数据库·python
Java面试题总结2 小时前
htop安装不了怎么解决
mysql
Zzxy2 小时前
HikariCP连接池
java·数据库
钰衡大师2 小时前
MySQL 数据库备份方案
数据库·mysql
殷紫川2 小时前
别等业务中断才补坑!RTO/RPO 核心逻辑与全场景灾备架构选型全攻略
数据库·架构
reasonsummer2 小时前
【办公类-133-02】20260319_学区化展示PPT_02_python(图片合并文件夹、提取同名图片归类文件夹、图片编号、图片GIF)
前端·数据库·powerpoint
2401_831920743 小时前
持续集成/持续部署(CI/CD) for Python
jvm·数据库·python
码哥字节3 小时前
如何在不停机的情况下保证迁移数据库数据的一致性?
数据库