磁盘结构与关键日志:Redo Log、Undo Log 与双写缓冲区

在上两篇文章中,我们走过了 InnoDB 的物理存储结构和内存架构。内存虽然快,但一断电就什么都没有了。数据库必须保证"已提交的数据不丢失"------这就是**持久性(Durability)**的要求。此外,事务的原子性(Atomicity)要求"要么全做,要么全不做",这需要回滚能力。而磁盘 I/O 本身充满风险:如果写入一页时突然断电,这一页就可能"撕裂",变成半新半旧的垃圾数据。

InnoDB 通过三大核心机制应对这些问题:Redo LogUndo LogDoublewrite Buffer。本文将逐个解析它们的作用、结构和工作原理,并引入 Checkpoint 概念,帮你把日志、磁盘和内存串联成一个完整的闭环。


1. Redo Log ------ 保证持久性的"重做日志"

1.1 为什么需要 Redo Log?

考虑一个简单的事务:执行一条 UPDATE,把某行的值从 'Hello' 改为 'World'。如果每次修改都要求立即把对应的数据页写回磁盘,会产生大量随机 I/O,性能难以接受。Buffer Pool 允许我们先在内存中修改,后台再慢慢刷盘。但如果在刷盘之前系统崩溃,内存中的修改就丢失了。

Redo Log 正是为了解决这个矛盾而生------它在修改 Buffer Pool 中的页之前,先把"做了什么修改"记录到 Redo Log 中,并立即写入磁盘 (这是顺序写,非常快)。即使崩溃,重启后也能通过 Redo Log 重做这些修改,恢复数据。这就是著名的 Write-Ahead Logging (WAL) 机制。

1.2 Redo Log 的文件与循环写入

Redo Log 在磁盘上由一组固定大小的文件组成,默认是两个(ib_logfile0ib_logfile1),大小由 innodb_log_file_size 控制。例如每个 512MB,总共 1GB。

这些日志文件是循环写入的:写完第一个文件写第二个,第二个写满后回到第一个文件开头重新写。这形成了一个逻辑上的环形结构。

复制代码
  ┌─────────────────────────────────────────────┐
  │              Redo Log 环形空间               │
  │                                             │
  │  ib_logfile0  ──→  ib_logfile1  ──→  (回到0) │
  └─────────────────────────────────────────────┘

显然,如果写得太快,新日志会把尚未刷盘的旧日志覆盖掉,这就会破坏持久性。因此 InnoDB 必须确保旧日志对应的脏页已经被刷盘,才允许覆盖。这就引出了 Checkpoint(检查点)

1.3 LSN:一切进度的标尺

**LSN(Log Sequence Number)**是一个单调递增的 8 字节数字,代表 Redo Log 的写入总量。每产生一个字节的 Redo 日志,LSN 就加一。

LSN 渗透在 InnoDB 的各个角落:

  • 每个数据页的头部存储着最近一次修改该页的 LSN
  • 每个日志块也有自己的 LSN。
  • Checkpoint 记录了"到哪个 LSN 为止的脏页都已刷盘"。

通过比较日志 LSN 和页 LSN,InnoDB 在崩溃恢复时就知道:哪些日志需要重做(页的 LSN < 日志 LSN),哪些不需要(页的 LSN >= 日志 LSN)。


2. Undo Log ------ 回滚与 MVCC 的基础

2.1 原子性如何实现?

一条 UPDATE 修改了数据,如果事务需要回滚,数据库必须把数据恢复成修改前的样子。这个"旧值"存放在哪里?答案是 Undo Log

Undo Log 记录了事务修改数据的"前镜像":如果是 INSERT,Undo 记录的是 DELETE 操作所需的信息;如果是 UPDATE,Undo 记录的是旧版本的值。当事务回滚时,通过 Undo Log 逆向执行这些操作,将数据恢复到事务开始前的状态。

2.2 Undo Log 的存储

与 Redo Log 的环形日志文件不同,Undo Log 存储在Undo 表空间 (默认在 innodb_undo_directory 下,可以配置独立文件)。它也是以页为单位组织的,支持随机读写。MySQL 8.0 默认创建两个 Undo 表空间,并支持自动截断(回收空间)。

2.3 Undo Log 与 MVCC

Undo Log 的另一个重要使命是支撑 MVCC(多版本并发控制) 。当一个事务修改一行时,InnoDB 会把当前行的 DB_ROLL_PTR(指向 Undo 记录的指针)更新到 Undo Log 中,形成一条版本链 。同时,行上的 DB_TX_ID 记录修改它的事务 ID。

其他并发查询事务,通过自己的 ReadView(可见性视图)来判断版本链中的哪个版本是"可见"的,从而读到自己应该看到的那个版本,而不是正在被其他事务未提交的修改。这就是"无锁读"的核心原理。我们在第五阶段 MVCC 篇会深入解读 ReadView。

对比 Redo 与 Undo

Redo Log Undo Log
作用 保证持久性(重启后重做) 保证原子性(回滚)、MVCC
记录内容 "做了什么修改"(物理+逻辑) "修改前的旧值"(逻辑)
存储位置 Redo Log 文件(环形) Undo 表空间(可随机读写)
生命周期 只在恢复时需要 需要保留到没有事务再需要它

3. Doublewrite Buffer ------ 页断裂的克星

3.1 什么是页断裂?

InnoDB 的页大小是 16KB,而操作系统的文件写入通常是 4KB 为单位。如果 MySQL 正在写入一个 16KB 页时突然断电,操作系统可能只写了前 8KB,后 8KB 仍然是旧的数据。这就叫页断裂(Torn Page)

一个断裂的页,校验和会出错,且无法用 Redo Log 修复(因为 Redo Log 记录的是"在某个完整页的基础上做了哪些修改",如果基础页面本身已损坏,重做也无法恢复)。

3.2 Doublewrite Buffer 的工作流程

InnoDB 使用双写缓冲区来应对页断裂:

  1. 脏页在刷盘之前,先顺序写入到双写缓冲区(系统表空间中一段连续的 128 页空间,即 2MB)。
  2. 双写缓冲区写入成功(因为是连续空间顺序写,速度快且可靠)后,再随机写入真正的表空间文件对应位置。
  3. 如果在随机写入时崩溃,导致页断裂,重启恢复时 InnoDB 会检测到页校验和不一致。此时,它可以从双写缓冲区中复制出该页的完整副本,再用 Redo Log 恢复。

这就给数据页增加了一层"安全保障",确保永远不会出现"页本身已损坏"的情况。

代价 :每次刷脏页都要写两遍,所以 Doublewrite Buffer 有一定性能开销。在极端注重 IOPS 的场景(如高端 SSD 原子写入 16KB 的场景),可以关闭它(innodb_doublewrite=0),但一般不建议。


4. Checkpoint ------ 连接日志与脏页的桥梁

前面提到,Redo Log 是循环使用的,不能无限写入。Checkpoint 就是一个"归档点",它告诉恢复机制:"比这个 LSN 更早的所有日志,对应的脏页都已写回磁盘,恢复时可以不用管它们。"

4.1 Checkpoint 的类型

InnoDB 有几种 Checkpoint:

  • Sharp Checkpoint:发生在正常关闭时,把所有脏页都刷盘,Redo Log 可以完全重用。
  • Fuzzy Checkpoint:运行时持续进行,每次只刷一部分脏页,将检查点 LSN 逐步向前推进。这是常态。

4.2 触发条件

Fuzzy Checkpoint 会在以下时机触发:

  • 定期(Master Thread 每 1 或 10 秒)。
  • Redo Log 空间不足,必须推进检查点以释放日志空间。
  • 脏页比例超过阈值。
  • 执行 FLUSH TABLES 等 DDL 操作时。

Checkpoint 推进的 LSN 将日志空间分为两部分:检查点之前的"干净区"(可覆盖),检查点之后的"活跃区"(不可覆盖)。


5. 日志间的协作全景图

让我们用一个完整的修改流程来串联 Redo、Undo、Doublewrite 和 Checkpoint:

  1. 事务开始:分配事务 ID,申请 Undo Log 空间。
  2. 修改行:在 Buffer Pool 中修改数据页,写入 Undo Log(旧值),生成 Redo Log 记录(新值及其改动信息)到 Log Buffer。
  3. COMMIT:Log Buffer 中的 Redo Log 被刷写到磁盘上的 Redo Log 文件。事务成为持久(Durability)。
  4. 脏页刷盘(稍后):后台线程将 Buffer Pool 中的脏页通过 Doublewrite Buffer 写入表空间文件。
  5. Checkpoint 推进:脏页成功刷盘后,Checkpoint LSN 向前移动,通知系统这些 Redo Log 空间可以复用。
  6. 崩溃恢复:重启时扫描 Redo Log,从最后一次 Checkpoint 开始重做所有日志。对于断裂页,先用 Doublewrite 副本修复,再重做。

通过这六大步骤,InnoDB 实现了"已提交的绝不丢失,未提交的可以回滚"的铁律。


6. 实战:查看 Redo Log 和 Checkpoint 信息

6.1 查看 Redo Log 配置

sql 复制代码
SHOW VARIABLES LIKE 'innodb_log_file_size';
SHOW VARIABLES LIKE 'innodb_log_files_in_group';
SHOW VARIABLES LIKE 'innodb_log_group_home_dir';

在操作系统上可以看到文件:

bash 复制代码
ls -lh /var/lib/mysql/ib_logfile*

6.2 查看 Checkpoint 和 LSN

SHOW ENGINE INNODB STATUSLOG 部分会显示当前 LSN 和 Checkpoint 信息:

复制代码
---
LOG
---
Log sequence number          123456789012
Log buffer assigned up to    123456789012
Log buffer completed up to   123456789012
Log flushed up to            123456789012
Log saved up to              123456789012
...
Last checkpoint at           123456788000
...
  • Log sequence number:当前最新 LSN。
  • Log flushed up to:已刷到磁盘的 LSN。
  • Last checkpoint at:最近一次 Checkpoint 的 LSN。

两者差值 Latest LSN - Checkpoint LSN 代表了"崩溃恢复时需要重做的日志量"。这个值不应该过大,否则恢复时间会很长。

6.3 查看 Undo 表空间

sql 复制代码
SELECT * FROM INFORMATION_SCHEMA.INNODB_TABLESPACES WHERE NAME LIKE 'innodb_undo%';

7. 小结

本文我们完成了对 InnoDB 关键日志和双写缓冲区的学习:

  • Redo Log:通过 WAL 机制把随机写转化为顺序写,保证已提交数据的持久性。循环写入,配合 Checkpoint 管理可用空间。LSN 是整个系统的时钟。
  • Undo Log:记录旧值,支持事务回滚(原子性)和 MVCC(多版本链),存储在 Undo 表空间中。
  • Doublewrite Buffer:防止页断裂,先顺序写双写缓冲区,再随机写表空间,牺牲少量性能换取数据页完整性。
  • Checkpoint:连接脏页与 Redo Log 的桥梁,通过推进检查点 LSN 来控制恢复时间和日志空间。

现在,你已经把 InnoDB 的磁盘结构、内存架构和日志机制串联了起来。下一篇文章我们将进入 崩溃恢复的全过程揭秘,详细剖析从启动到恢复完成的每一步,并用模拟宕机实验亲眼见证 Redo Log 如何拯救数据。

思考题

  1. 如果 innodb_log_file_size 设置得太小,会发生什么现象?
  2. 为什么不直接关闭 Doublewrite Buffer 来提升性能?什么情况下可以安全地关闭它?
  3. Undo Log 记录的是什么?它和 Redo Log 记录的内容有什么本质区别?

参考资料


相关推荐
鹤落晴春17 小时前
RH124问答3:从命令行管理文件
linux·运维·服务器
火山上的企鹅18 小时前
Codex实战:APP远程升级服务搭建(三)后台管理页面(APK 上传、版本管理、多应用页签)
服务器·网络·数据库·oracle·qgc
❀搜不到19 小时前
远程服务器codex使用本地cc-switch的deepseek api
运维·服务器
阿狸猿19 小时前
论 NoSQL 数据库技术及其应用
数据库·nosql
FBI HackerHarry浩19 小时前
DataGrip2023.2.3默认保存的数据库和.sql文件在哪里?怎么修改默认路径?
数据库
袁小皮皮不皮19 小时前
3.HCIP OSPF补充知识(优化版)
服务器·网络·数据库·网络协议·智能路由器
运筹vivo@19 小时前
Python ContextVar 底层机制与内存模型拆解
前端·数据库·python
志栋智能20 小时前
超自动化巡检:知识沉淀与团队协作的新载体
大数据·运维·网络·数据库·人工智能·自动化
syt_biancheng20 小时前
Redis初识
数据库·redis·缓存
袁小皮皮不皮20 小时前
1.HCIP BFD 学习笔记(优化版)
服务器·网络·笔记·网络协议·学习·智能路由器·ip