数据库突然断电,凭什么没丢数据?——WAL 日志与崩溃恢复

数据库突然断电,凭什么没丢数据?------WAL 日志与崩溃恢复

数据库 · 事务与可靠性。这篇文章讲 redo/undo 日志、WAL(Write-Ahead Logging)协议,以及崩溃后数据库如何靠日志"恢复如初"------这是理解数据库可靠性的底层。

一次"拔电源"的粗暴测试

有次做数据库的容灾演练,DBA 直接在生产库上按了断电按钮(当然是演练环境)。我心想:正在写一半的数据,这下肯定坏了吧?结果重启之后,数据库花了几秒"恢复",数据一条没丢,那些写了一半没提交的事务也干干净净地回滚了。

我问 DBA:断电那一刻,内存里的数据不是全没了吗?他说了一句我记到现在的话:"内存里的数据丢了没关系,因为真正算数的东西,早就写到日志里了。"

那个"真正算数的东西",就是数据库的日志 ,以及它背后一条铁律------WAL(Write-Ahead Logging,先写日志)。这篇文章就把这套机制讲清楚。

为什么不能"直接改数据"

最直觉的做法是:事务要改哪条数据,就直接在磁盘上改哪条。可这里有个致命矛盾:

  • 改到一半断电了怎么办?------数据可能"改了一半",既不是旧值也不是新值,直接损坏;
  • 事务改了但没提交,改到一半又回滚了怎么办?------磁盘上已经被改花,回滚还得再写回去,既慢又危险。

于是数据库想了个办法:把"我要做什么"先记在日志里,日志写稳了,再去动数据。 日志是顺序追加的、结构简单、写起来快,而且能完整记录"改前长什么样、改后长什么样"。

WAL:先写日志,再改数据

WAL 协议的核心就一句话:在对数据页做任何修改之前,必须先把对应的日志记录落盘(flush 到磁盘)。

text 复制代码
1. 事务要修改数据
2. 先把"改前值 + 改后值"写成一条日志,落盘
3. 日志落盘成功,才允许修改内存/磁盘上的数据
4. 提交时,再落一条"提交"日志

为什么要"先"?因为日志是顺序写 (append-only),数据页是随机写 ,顺序写比随机写快得多。把慢的随机写"延迟"到后面批量做,把快的顺序写"提前"做,既保证安全又提升性能。日志就是那本"先记账、后发货"的账本。

redo 与 undo:两本账,管两件事

日志里通常记两类信息,对应两种恢复动作:

  • redo 日志 :记"改后值"(新值)。作用是重做 ------崩溃后,把"已经提交、但还没来得及写进数据页"的修改,照着日志再执行一遍,保证提交了的一定不丢。
  • undo 日志 :记"改前值"(旧值)。作用是撤销 ------崩溃后,把"没提交、却已经把修改写进去了"的事务,照着日志回滚掉,保证没提交的一定不生效。

一句话分工:

text 复制代码
redo  → 提交了的,一定让它生效(重做)
undo  → 没提交的,一定让它消失(撤销)

两者配合,就能在崩溃后把数据库恢复到一个"所有已提交事务生效、所有未提交事务回滚"的一致状态。

崩溃恢复:重启后那几秒在干什么

你看到的"正在恢复",其实就是数据库在重放日志:

text 复制代码
1. 扫描日志,找到最后一个检查点(checkpoint,定期把数据刷盘并记录位置)
2. 从检查点往后,收集所有已提交、未提交的事务
3. 对已提交的 → 重做 redo(把修改补上)
4. 对未提交的 → 回滚 undo(把修改撤销)
5. 数据页和数据一致了,恢复完成

检查点(checkpoint) 的作用是"缩短恢复时间":没有它,每次崩溃都得从头扫日志;有了它,只需从最近一个检查点往后重放,恢复快得多。

为什么这套设计这么重要

它同时解决了三个看起来矛盾的需求:

  1. 性能:先顺序写日志,把慢的随机写数据页延迟、合并,事务吞吐大幅提升;
  2. 原子性:崩溃后靠 undo 把"半截子事务"撤销干净;
  3. 持久性:崩溃后靠 redo 把"已提交事务"找补回来。

这三条合起来,正是事务 ACID 里的 A(原子性)和 D(持久性) 的工程实现。所以 WAL 几乎是所有主流数据库(MySQL InnoDB、PostgreSQL、SQLite)的标配,也顺带催生了"日志即数据"这一整套现代存储思想。

所以下次再看到数据库启动时那一行"正在恢复(recovery)",别慌------它不是坏了,而是在把账本重新过一遍,保证"说过的每一笔都算数"。

数据库的日志与恢复,和操作系统、文件系统里的"日志/回放"思路一脉相承,属于理解存储可靠性的通用视角。

相关推荐
Warolitbos1 小时前
【数据库】SQL面试基础15题,测试/开发必背速查
数据库
用户84913717547161 小时前
【技术干货】MySQL联合索引底层原理 | 最左前缀原则详解
mysql·面试
kele_z2 小时前
手工修改数据库中的数据时,我会加的四道保险
mysql·postgresql
ly76892 小时前
PostgreSQL 执行计划深读:从 EXPLAIN 输出到代价模型驱动的 SQL 改写
数据库·sql·postgresql·explain·执行计划·代价模型
Python自动化直播2 小时前
自动化笔记:素材管理、命名、轮换的几条土办法
linux·运维·数据库
xiaomuzuirenzhen2 小时前
2027校招ERP实施顾问:大数据管理与应用专业如何用SQL、BI证明业务能力
大数据·数据库
eleven_4u2 小时前
MySQL深分页如何处理
mysql
底层玩家老张3 小时前
从副本集到分片:百亿级文档数据的KES架构边界
数据库·分布式架构·分片·架构选型·文档数据库
ss2733 小时前
AI时代首先数据库-PostgreSQL实战笔记 | 16 PostgreSQL子查询与嵌套查询(下)
数据库·笔记·postgresql