WAL 与 ARIES:pageLSN、CLR 与可重启恢复
内容提要
ARIES 针对 steal/no-force 缓冲策略下的崩溃恢复顺序问题,采用先重做历史到崩溃点、再撤销未完成事务的流程,且撤销过程可再次恢复。其核心机制包括 LSN、pageLSN、ATT、DPT 和 CLR,恢复分为 Analysis、Redo、Undo 三阶段。实验通过随机崩溃及恢复中再崩溃验证了机制的正确性。PostgreSQL 16 仅实现 WAL redo,并非完整 ARIES;SQLite WAL 则采用页帧序列模型。
延伸解读
ARIES 与 PostgreSQL 恢复模型的差异
文章指出 PostgreSQL 16 仅实现 WAL redo,没有 ARIES 的逻辑 undo 阶段。未提交行版本依靠 MVCC 可见性和事务状态处理,后续由清理过程回收。这与 ARIES 的 undo loser transactions 直到 END 的模型不同。因此,不能将 PostgreSQL 简单归类为完整 ARIES,其恢复机制更依赖 MVCC 和清理。
SQLite WAL 的页帧序列模型
SQLite 3.46 的 WAL 文件由 32 字节 header 和若干 frame 构成,每个 frame 包含 24 字节 frame header 和一整页内容。事务在写入带 commit marker 的 frame 时提交。读事务记录 mxFrame,并在不超过该 frame 的范围内寻找页的最后有效版本。checkpoint 时先对 WAL 做 VFS.xSync,再将有效内容搬回数据库文件并同步。这不同于 ARIES 的 steal/no-force + CLR 模型。
CLR 在恢复中再次崩溃时的作用
文章通过示例说明,如果 undo 过程中写入 CLR 后再次崩溃,下一次恢复会 redo 包括 CLR 在内的日志,然后从 loser 事务的 lastLSN 开始 undo。遇到 CLR 时,会直接跳到 UndoNxtLSN,避免重复撤销已撤销的更新。这体现了 CLR 的价值:使恢复过程本身可恢复,确保已撤销的更新不会被重复撤销。
WAL 恢复实现的检查要点
文章最后给出工程检查清单,强调实现或审阅 WAL 恢复代码时需验证:刷脏页前保证 pageLSN <= flushedLSN;提交返回前保证 commit record 已持久化;checkpoint 记录精确刷盘点还是 fuzzy 状态;redo 是否用 pageLSN 判重;undo 是否先写 CLR 再推进 UndoNxtLSN;生产系统是否真有 ARIES undo。这些检查点有助于避免恢复错误。
Q&A
ARIES 恢复算法为什么需要 redo 和 undo 两个阶段?
因为 ARIES 采用 steal/no-force 缓冲策略:允许未提交脏页刷盘,且提交时不强制刷数据页。这导致崩溃后磁盘可能缺少已提交更新(需要 redo)又包含未提交更新(需要 undo)。因此恢复时必须先重做历史到崩溃点,再撤销未完成事务。
ARIES 中的 pageLSN 有什么作用?
pageLSN 是数据页上已经包含的最新日志 LSN,用于判断某条日志记录是否需要重做。如果页面的 pageLSN 已经不小于该记录的 LSN,说明该记录的效果已经在页上,可以跳过重复 redo。
CLR 是什么?它如何保证恢复过程本身可恢复?
CLR(Compensation Log Record)记录一次 undo 的结果和 UndoNxtLSN。当撤销一条更新时,先写 CLR,再推进 UndoNxtLSN。如果恢复中再次崩溃,下次恢复看到 CLR 会直接跳到 UndoNxtLSN,避免重复撤销已撤销的更新,从而使恢复过程可重启。
ARIES 的 Analysis、Redo、Undo 三个阶段分别做什么?
Analysis 从最近 checkpoint 扫描到日志末尾,重建 ATT 和 DPT,确定 redo 起点;Redo 从 min(DPT.recLSN) 开始顺序重做历史,包括已提交和未提交事务的更新,并用 pageLSN 等条件过滤;Undo 对 loser transactions 沿 prevLSN 反向撤销,每撤销一条写一条 CLR。
PostgreSQL 16 的恢复机制是完整的 ARIES 吗?
不是。PostgreSQL 16 有 WAL、checkpoint、redo 起点和 full-page image,但恢复时没有 ARIES 的逻辑 undo 阶段。未提交行版本依靠 MVCC 可见性和事务状态存储处理,后续由清理过程回收,这与 ARIES 的 undo loser transactions 模型不同。
SQLite 的 WAL 模式与 ARIES 有什么不同?
SQLite WAL 文件是页帧序列,由 32 字节 header 和若干 frame 构成,每个 frame 包含 24 字节 frame header 加一整页内容,事务在写入带 commit marker 的 frame 时提交。它采用单写者约束、页帧校验、salt 和 wal-index 组织恢复,而不是 ARIES 的 steal/no-force + CLR 模型。
ARIES 实验如何验证恢复机制的正确性?
实验使用内存页级 ARIES 模拟器,随机生成事务、随机刷出脏页、在随机步数崩溃,并在第一次 undo 写出一条 CLR 后再次模拟崩溃。第二次恢复必须得到只包含已提交事务更新的页面集合,且不能重复撤销已有 CLR 的更新。结果中总 CLR 数与 loser 更新总数一致,验证了机制正确。