数据库日志
数据库日志是事务回滚、崩溃恢复、版本可见性和复制链路的基础设施,不等于普通应用日志。
#type / concept
#status / growing
#tech / dev / backend
#resource / database
[!info] related notes
数据库日志
一句话定义
数据库日志是数据库为了支撑事务回滚、崩溃恢复、版本可见性、复制和审计而维护的内部记录,不是普通应用打印信息。
它要解决什么问题
数据库不是每次修改都立刻把最终结果完整写回磁盘。
这带来几个关键问题:
- 事务失败时,怎么撤销已经做过的修改
- 提交成功但脏页还没刷盘时宕机,怎么恢复
- 想读旧版本时,旧值从哪里来
- 主从复制或时间点恢复时,变更事实如何传递
数据库日志就是这些能力的共同基础设施。
核心机制 / 工作原理
1. 日志的核心价值是“先记下来,再决定怎么恢复”
数据库日志的本质不是给人看的说明文,而是给数据库自己用的恢复依据。
它记录的重点通常包括:
- 改动前是什么
- 改动后要变成什么
- 哪个事务做了这次修改
- 这次修改是否已经提交
数据库之所以敢先在内存里改页、后面再慢慢刷盘,就是因为日志先把恢复依据保住了。
2. 事务相关日志至少服务四类职责
- 回滚未提交事务
- 崩溃后重做已提交事务
- 支撑旧版本可见性
- 对外复制或时间点恢复
虽然这些职责都叫“日志”,但并不意味着它们是同一种东西。
3. write-ahead logging 是理解日志系统的第一原则
一个非常关键的原则是:
- 先写日志
- 再写数据页
这样即使数据库在数据页刷盘之前崩溃,只要日志已经安全落盘,恢复流程就还能把已提交的结果重建出来。
所以提交成功的关键不是“表文件已经写完”,而是“恢复所需信息已经可靠保存”。
4. 不同数据库、不同日志,职责各不相同
常见例子包括:
- PostgreSQL 的 WAL:偏重预写日志、崩溃恢复和复制基础
- MySQL InnoDB 的 Redo Log:偏重已提交修改的重做
- MySQL InnoDB 的 Undo Log:偏重回滚和旧版本可见性
- MySQL 的 Binlog:偏重对外传播变更、复制和时间点恢复
理解数据库事务时,最怕把这些日志全当成“差不多的东西”,因为它们服务的阶段和目标并不一样。
最小例子 / 最小场景
一次订单状态更新已经 COMMIT 成功,但数据页还没真正刷回磁盘时数据库宕机了:
- 如果没有日志,数据库很难知道这次修改到底应不应该存在
- 如果恢复日志已经安全落盘,数据库重启后就能把这次已提交修改重做出来
这就是为什么事务持久性并不要求“提交瞬间所有数据页都写完”。
从原理上,最该先区分哪几类日志
1. 用于撤销的日志
核心问题是:
- 事务失败时怎么回到旧状态
- 旧版本从哪里来
典型例子是 Undo Log。
2. 用于重做的日志
核心问题是:
- 已提交但尚未来得及刷盘的修改,宕机后怎么补回来
3. 用于复制或外部消费的日志
核心问题是:
- 数据库发生了哪些变更,其他系统如何知道
典型例子是 Binlog。