Redo 日志详解

什么是 Redo 日志

Redo 日志 = 用来重做操作的日志

记录的是”修改后的值”(新值),用于在系统崩溃后重做已提交事务的修改。

为什么需要日志

在数据库系统中,日志是保证数据持久性和原子性的核心机制:

  • 事务可能失败:程序崩溃、系统宕机、硬件故障
  • 我们需要恢复:故障后要能恢复到一致状态
  • 日志是关键:先写日志再写数据(WAL - Write-Ahead Logging)

Redo 日志格式

[Redo Log] <事务ID, 表名, 主键, 列名, 新值>

具体示例

场景:银行转账 - 张三的账户从 1000 元扣款 200 元

初始状态

账户表 (accounts)
+----+--------+-------+
| id | name   | money |
+----+--------+-------+
| 1  | 张三   | 1000  |
| 2  | 李四   | 500   |
+----+--------+-------+

执行 UPDATE 操作

UPDATE accounts SET money = money - 200 WHERE id = 1;

生成的 Redo 日志

Redo Log: <事务T1, accounts, id=1, money, 新值=800>

流程图解

flowchart TD
    A[开始事务 T1] --> B[执行 UPDATE<br/>money: 1000 → 800]
    B --> C[记录 Redo 日志<br/>money: 新值=800]
    C --> D[提交事务]
    D --> E{系统正常还是崩溃?}
    
    E -->|正常| F[事务完成<br/>数据已持久化]
    E -->|崩溃后恢复| G[读取 Redo 日志]
    G --> H[检查事务状态]
    H -->|已提交| I[重做操作<br/>应用新值]
    H -->|未提交| J[跳过此操作]
    
    style F fill:#90EE90
    style I fill:#87CEEB

Redo 日志的特点

特点说明
顺序写入Redo 日志是顺序写的,比随机写数据页快很多
物理日志记录的是物理页的变化
持久化事务提交前必须确保 Redo 日志已落盘
崩溃恢复用于恢复已提交事务的修改

Redo 日志的存储

  • InnoDB:ib_logfile0, ib_logfile1(循环写入)
  • Oracle:在线重做日志文件(Online Redo Log)
  • SQL Server:事务日志文件(.ldf)

WAL(Write-Ahead Logging)原则

先写 Redo 日志,再写数据页。如果数据页先写入了,但系统崩溃,Redo 日志丢失,就会导致数据不一致。先写 Redo 日志,即使数据页没写入,也能通过 Redo 恢复。

事务开始
    ↓
记录 Redo 日志(修改后的值)
    ↓
Redo 日志刷盘 ← 关键!确保持久性
    ↓
提交事务
    ↓
数据页异步刷盘(可延迟)
    ↓
事务结束

Redo 日志与崩溃恢复

崩溃前状态

事务T1:已提交,但数据未刷盘
事务T2:未提交,已修改数据

恢复后

1. 扫描 Redo 日志
2. T1 已提交 → 重做 T1 的修改 ✓
3. T2 未提交 → 配合 Undo 日志回滚

实际日志示例(InnoDB)

-- Redo日志示例(内部结构)
Redo Log Entry:
  Type: MLOG_UPDATE_WRITE
  Space ID: 1
  Page Number: 5
  Offset: 100
  Data: (id=1, name='张三', balance=800)

类比:Redis 的 AOF

Redis 机制对应数据库概念
AOF(Append Only File)Redo 日志
RDB(快照)数据页备份
AOF重写压缩日志

面试要点

Q:为什么 Redo 日志要先于数据页写入?

A:这就是 WAL 原则。如果数据页先写入了,但系统崩溃,Redo 日志丢失,就会导致数据不一致。先写 Redo 日志,即使数据页没写入,也能通过 Redo 恢复。

Q:Redo 日志文件为什么是循环使用的?

A:为了控制文件大小,采用循环写入策略。新数据覆盖旧数据,但覆盖前要确保相关修改已刷盘。

参考链接