跳转至

Recovery with ARIES 学习笔记

CMU 15-445/645 Intro to Database Systems — Recovery II: ARIES

关于本笔记

本讲承接 Database Logging,说明系统崩溃后如何利用 WAL、LSN、Dirty Page Table 和 Active Transaction Table 恢复数据库。ARIES 的核心是:先重复历史,再撤销不该留下的修改。

1 ARIES 概述

ARIES 全称是 Algorithms for Recovery and Isolation Exploiting Semantics,是数据库崩溃恢复的经典算法。它假设系统使用:

  • Steal + No-Force buffer pool policy。
  • Write-Ahead Logging。
  • 单版本事务模型,通常配合 strict 2PL 讨论。

ARIES 的三个核心思想:

  1. Write-Ahead Logging:数据页落盘前,对应日志必须先落盘。
  2. Repeating History During Redo:REDO 阶段重放崩溃前发生过的历史,包括后来要回滚的事务。
  3. Logging Changes During Undo:UNDO 也写日志,使用 Compensation Log Record (CLR) 记录撤销进度。

2 LSN 与基础元数据

Log Sequence Number (LSN) 是日志记录的全局递增编号,用来表示日志顺序。

名称 含义
LSN 当前日志记录的编号
prevLSN 同一事务上一条日志记录,用于反向遍历
pageLSN 页面上最近一次修改对应的 LSN
flushedLSN WAL 已经刷到磁盘的最大 LSN
recLSN 某页变脏后第一条修改它的日志记录
lastLSN 某事务最近一条日志记录
Master Record 记录最近一次成功 checkpoint 的位置

页面能否写回磁盘的关键判断:

pageLSN <= flushedLSN

如果 pageLSN 大于 flushedLSN,说明页面包含的某些修改还没有日志落盘,直接刷页会违反 WAL。

3 日志记录类型

类型 作用
BEGIN 事务开始
UPDATE 记录一次页面修改,包含 before/after image
COMMIT 事务决定提交;刷到磁盘后可向客户端确认
ABORT 事务开始回滚
CLR 记录一次 UNDO 的补偿操作
END 事务彻底结束,可从内部表移除
BEGIN_CHECKPOINT / END_CHECKPOINT fuzzy checkpoint 的边界

COMMITEND 不同:COMMIT 表示事务对外成功;END 是系统内部清理完成的标记。提交记录必须及时刷盘,END 可以随之后的日志批量刷出。

3.1 Compensation Log Record

CLR 是“撤销某条 update”的日志记录。它有两个特点:

  • CLR 会在 REDO 阶段重放。
  • CLR 不会再次被 UNDO。

CLR 中的 undoNextLSN 指向该事务下一条仍需撤销的日志记录。这样即使系统在 UNDO 过程中再次崩溃,下一次恢复也能跳过已经撤销过的部分。

4 内存表

ARIES 恢复过程中维护两张关键表:

内容 作用
Active Transaction Table (ATT) txn_id -> status, lastLSN 找到崩溃时仍未结束的事务
Dirty Page Table (DPT) page_id -> recLSN 找到可能没有刷盘的页面,以及 REDO 起点

事务状态通常包括:

  • RUNNING:正常执行。
  • COMMITTING:已经看到 commit,但还没看到 end。
  • RECOVERY_ABORTING:恢复过程中需要回滚。
  • COMPLETE:已经写入 end,可移出 ATT。

5 Fuzzy Checkpoint

阻塞式 checkpoint 会暂停事务,性能太差。ARIES 使用 fuzzy checkpoint

  1. 写入 BEGIN_CHECKPOINT
  2. 记录 checkpoint 开始时的 ATT 和 DPT。
  3. 事务继续运行,checkpoint 后台完成。
  4. 写入 END_CHECKPOINT,其中包含 ATT/DPT 快照。
  5. END_CHECKPOINT 刷盘后,更新 master record 指向 BEGIN_CHECKPOINT

Fuzzy checkpoint 不保证 checkpoint 期间页面完全静止,因此恢复时仍需从日志中分析 checkpoint 前后的变化。

6 三阶段恢复流程

6.1 Analysis

Analysis 从 master record 指向的最近 checkpoint 开始,向前扫描到日志末尾,重建 ATT 和 DPT。

主要规则:

  • 遇到事务日志记录,把事务加入 ATT,并更新 lastLSN
  • 遇到 UPDATECLR,如果页面不在 DPT 中,加入并设置 recLSN 为当前 LSN。
  • 遇到 COMMIT,把事务状态改为 COMMITTING
  • 遇到 END,从 ATT 中移除事务。
  • 扫描结束后,仍在 ATT 中且未提交的事务是 loser transactions,需要 UNDO。
  • 已提交但没有 END 的事务是 winner transactions,可补写 END 并移除。

Analysis 结束后:

  • ATT 告诉系统哪些事务崩溃时还没结束。
  • DPT 告诉系统哪些页面可能需要 REDO。

6.2 Redo

Redo 的目标是把数据库恢复到“崩溃瞬间”的状态。它从 DPT 中最小的 recLSN 开始向前扫描,并重放必要的 UPDATECLR

对一条日志记录 r,只有满足以下条件才需要 redo:

  1. r 修改的页面在 DPT 中。
  2. r.LSN >= DPT[page].recLSN
  3. 从磁盘读入该页后,pageLSN < r.LSN

如果 pageLSN >= r.LSN,说明该修改已经在磁盘页中,不需要重复应用。重放时直接应用 after image 或 CLR 的补偿修改,然后把页面的 pageLSN 设为 r.LSN

为什么要重复历史

ARIES 即使知道某个事务最终要回滚,也会先在 REDO 阶段重放它的修改。这样可以先还原崩溃时的完整状态,再由 UNDO 阶段按统一规则清理 loser transactions。

6.3 Undo

Undo 处理 Analysis 后仍留在 ATT 中的 loser transactions。系统通常维护一个按 LSN 倒序处理的集合 ToUndo

  1. 初始化为每个 loser transaction 的 lastLSN
  2. 取最大的 LSN,找到对应日志记录。
  3. 如果是普通 UPDATE,应用 before image 反向修改页面,并写入 CLR。
  4. 如果该记录还有 prevLSN,把 prevLSN 加入 ToUndo;否则写入 END
  5. 如果遇到 CLR,沿 undoNextLSN 继续跳转,不再撤销 CLR 本身。

UNDO 每撤销一步就追加 CLR,因此恢复过程可以重复崩溃。下一次 REDO 会重放已经写出的 CLR,新的 UNDO 只需要从尚未完成的位置继续。

7 恢复中再次崩溃

崩溃位置 处理方式
Analysis 中崩溃 不需要特殊处理,重新开始恢复
Redo 中崩溃 Redo 是幂等的,重新开始即可
Undo 中崩溃 已写出的 CLR 会在下一次 Redo 中重放,Undo 继续剩余部分

这就是 CLR 的价值:它让系统能够记录“已经撤销到哪里”,避免每次崩溃后从头回滚同一批修改。

8 小结

ARIES 把崩溃恢复拆成清晰的三步:Analysis 先弄清崩溃时系统状态,Redo 重放历史到崩溃点,Undo 再清除 loser transactions。配合 WAL、LSN、fuzzy checkpoint、ATT、DPT 和 CLR,数据库可以在 Steal + No-Force 的高性能策略下仍然保证原子性和持久性。