WAL
WAL = Write-Ahead Logging(预写日志)
核心思想:先记录日志,再修改数据
- 所有对数据库的修改,先写入 WAL 日志文件
- 只有日志写入成功,事务才算提交
- 数据页可以延迟刷盘,保证崩溃恢复时可回滚或重做
-
事务持久性(Durability)
- 数据修改未落盘,系统崩溃也能恢复
-
崩溃恢复(Crash Recovery)
- 系统挂掉,重放 WAL 可恢复未落盘的数据
-
高性能写入
- 避免每次修改都直接刷磁盘
- 顺序写日志比随机写数据快很多
-
支持复制
- WAL 可用于流复制(PostgreSQL)或 binlog(MySQL)
- 事务修改 -> 写 WAL 日志
- 日志刷盘(fsync) -> 事务提交
- 脏页延迟刷盘 -> 数据页异步写入磁盘
- 崩溃恢复:
- Redo 日志:回放 WAL,保证修改持久
- Undo 日志:回滚未提交事务(部分数据库通过 MVCC 或 redo/undo 实现)
事务开始
|
v
修改 -> 写 WAL
|
v
fsync WAL(保证持久)
|
v
事务提交
|
v
异步写入数据页
以 PostgreSQL 为例:
-
WAL 记录结构
- Log Sequence Number (LSN):每条 WAL 的唯一标识
- 页级修改记录:记录数据页变化
- 事务号、时间戳、操作类型
-
磁盘布局
- WAL 分段文件(通常 16MB/32MB)
- 顺序写入,追加模式
- 顺序 fsync,避免随机写
-
WAL 重放
- 按 LSN 顺序扫描
- redo 修改数据页
- undo 撤销未提交事务
| 特性 | PostgreSQL WAL | MySQL InnoDB redo log |
|---|---|---|
| 叫法 | WAL | redo log (也称 redo) |
| 事务提交 | WAL 写入 fsync -> 提交 | redo log 写入 buffer -> flush 或 group commit |
| 数据页写入 | 异步刷脏页 | 异步刷脏页 |
| 文件类型 | WAL segment files | redo log files (循环) |
| 事务恢复 | 通过重放 WAL | redo log 重做,undo log 回滚 |
| MVCC 关系 | 直接支持 MVCC | InnoDB MVCC 使用 undo log |
| 复制 | WAL 可流复制 | binlog 复制(逻辑复制) |
-
顺序写优势
- WAL 写入顺序,磁盘 IO 效率高
-
fsync 策略
- 每事务 fsync -> 最安全,但慢
- batch fsync / group commit -> 性能高
-
日志压缩/分段
- PostgreSQL 分段文件
- MySQL redo 循环日志
-
异步刷盘
- 数据页可以延迟写入,提高吞吐
-
崩溃恢复
- PostgreSQL 挂掉 -> 重放 WAL -> 完整恢复
- MySQL InnoDB 崩溃 -> redo log 回滚/重做
-
逻辑/流复制
- PostgreSQL 流复制 -> 直接传 WAL
- MySQL binlog -> redo + binlog 逻辑复制
-
热备 / 增量备份
- WAL 可增量备份
- 支持 PITR(Point-In-Time Recovery)
WAL 是数据库保证事务持久性和崩溃恢复的核心机制:修改先写日志再改数据页,日志顺序写磁盘,高性能并支持复制和增量备份。