这是《PostgreSQL 零基础实战指南》的独立章节版。本章从概念、实操和生产排查三个视角展开,代码块保留了原书可直接运行的版本。 WAL(Write-Ahead Logging)先写日志再改数据页,是崩溃恢复、归档备份和流复制的基础。
16.1 基本原理
事务提交
-> WAL 记录写入 wal_buffers
-> 按提交策略刷入 WAL 文件
-> 后台进程逐步刷脏数据页
崩溃后从检查点重放 WAL,把数据库恢复到一致状态。
16.2 核心参数
SHOW wal_level;
SHOW max_wal_size;
SHOW min_wal_size;
SHOW checkpoint_timeout;
SHOW synchronous_commit;
SHOW archive_mode;
SHOW archive_command;
| 参数 | 说明 |
|---|---|
| wal_level | minimal / replica / logical |
| max_wal_size | 检查点目标上限 |
| checkpoint_timeout | 检查点间隔 |
| synchronous_commit | 是否等待 WAL 刷盘 |
| archive_mode | 是否归档 |
16.3 检查点
检查点把脏页刷到数据文件,并记录 WAL 恢复起点。
手动:
CHECKPOINT;
查看:
SELECT * FROM pg_stat_bgwriter;
检查点过于频繁会增加 IO;过于稀疏会延长崩溃恢复时间。
16.4 synchronous_commit
| 值 | 语义 |
|---|---|
| on | 等待本地 WAL 刷盘 |
| off | 异步提交,可能丢最近事务 |
| remote_apply | 等待备库回放 |
| remote_write | 等待备库写入 |
| local | 等待本地刷盘,不等备库 |
金融核心交易通常保持 on 或 remote_apply;日志类可评估异步,但必须明确丢失窗口。
16.5 WAL 归档
配置:
wal_level = replica
archive_mode = on
archive_command = 'test ! -f /archive/%f && cp %p /archive/%f'
查看:
SELECT * FROM pg_stat_archiver;
归档目录要有容量监控和保留策略,且应存独立存储。
16.6 PITR
基础备份 + 归档 WAL 可做时间点恢复。
配置恢复目标:
restore_command = 'cp /archive/%f %p'
recovery_target_time = '2026-08-25 12:00:00+08'
恢复前要确认:
- 备份完整性;
- WAL 连续;
- 恢复目标时间;
- 是否包含时区;
- 恢复到新实例验证。
16.7 WAL 大小治理
查看:
SELECT pg_current_wal_lsn();
SELECT pg_size_pretty(pg_wal_lsn_diff(pg_current_wal_lsn(), '0/0'));
WAL 增长原因:
- 大批量写入;
- 高频更新;
- 索引过多;
- 归档失败;
- 复制槽保留;
- 检查点配置;
- 长恢复窗口。
16.8 复制槽
SELECT slot_name, slot_type, active, restart_lsn
FROM pg_replication_slots;
失效复制槽会保留 WAL,导致磁盘被占满。逻辑订阅必须有监控和清理策略。
本章小结
WAL 用顺序日志换取崩溃恢复和复制能力。生产要理解提交策略、检查点、归档、PITR 和复制槽的关系,并持续监控 WAL 生成与保留。
思考题
- 为什么先写 WAL 再刷数据页?
- synchronous_commit 各级别有什么差异?
- 检查点参数如何影响 IO?
- 复制槽为什么会占满磁盘?
- PITR 需要哪些备份条件?