第 8 章 · 04 预写日志(WAL)与崩溃恢复 本节摘要:数据库最怕「写一半断电」。预写日志(WAL,Write-Ahead Log)是解决这个问题的标准方案:先把要做的改动记进日志(顺序写,快),再改实际数据(随机写,慢)。崩溃后重放日志,要么把没做完的做完,要么把没提交的撤销。本节讲清 WAL 的工作原理与崩溃恢复流程,这是「持久性」的工程实现,呼应第 6 章 Git 的「原子提交」思想。 内容来源:基于数据库持久化整理的导读。 学习目标 说清 WAL 的核心:「先记日志,再改数据」。 解释为什么先写日志(顺序写快)再改数据(随机写慢)反而更可靠。 描述崩溃恢复:重放日志,补做未完 / 撤销未提交。 理解 WAL 与第 6 章 Git 原子提交思想的呼应。
本节摘要:数据库最怕「写一半断电」。预写日志(WAL,Write-Ahead Log)是解决这个问题的标准方案:先把要做的改动记进日志(顺序写,快),再改实际数据(随机写,慢)。崩溃后重放日志,要么把没做完的做完,要么把没提交的撤销。本节讲清 WAL 的工作原理与崩溃恢复流程,这是「持久性」的工程实现,呼应第 6 章 Git 的「原子提交」思想。
内容来源:基于数据库持久化整理的导读。
数据库的 ACID 里,「D(持久性)」——提交了就不丢——是最难保证的。磁盘写一半断电,数据可能损坏。WAL 是工业界的标准解法,几乎所有数据库(SQLite、MySQL、PostgreSQL)都用它。理解 WAL,你才理解「为什么数据库能承诺持久性」,以及「fsync 为何重要」。
朴素做法:每次修改直接改数据页,定期刷盘。问题:改一个数据页可能跨多个磁盘块,写到一半断电,这个页就损坏了。而且数据页是随机写(改哪写哪),慢。
修改操作: 1. 把「要做什么改动」记进 WAL 日志(追加, 顺序写, 快) 2. fsync 日志(确保日志真落盘) 3. 才改实际数据页(随机写, 慢, 可延迟批量刷盘)
关键:日志先落盘,数据后改。崩溃后:
这样,只要「日志写了」就算「提交成功」,数据页可以慢慢刷盘(性能好),崩溃靠日志恢复。
顺序写(日志追加)比随机写(改数据页)快几个数量级(磁盘的机械特性:顺序不用移动磁头,SSD 顺序也更快)。WAL 把「确保可靠」的负担放在快的顺序写上,把慢的随机写延迟批量做——既可靠又快。
启动时检查 WAL:
恢复后,数据页状态 = 最后一次提交的完整状态——持久性得到保证。
第 6 章造 Git 时,commit 是「原子的」(要么完整存在,要么不存在)。WAL 让数据库也获得类似原子性:事务要么完整(日志写了)、要么不存在(日志没写),不会「半提交」。两者都靠「先写不可变记录,再改可变状态」的模式。
下一节讲事务 ACID 与综合。