先写日志,后写数据
写入一条小的顺序日志记录,比随机更新数据页更便宜。更重要的是,它给数据库一份有序历史。事务把变更写入 WAL,提交时刷新日志并报告成功;数据页由后台进程稍后写入。如果进程崩溃,恢复过程从最后一个检查点重放日志,把数据文件带到一致状态。
SHOW wal_level;
SELECT pg_current_wal_lsn();
SELECT * FROM pg_stat_wal;
wal_level、synchronous_commit 和 fsync 是策略设置,不是无关紧要的调优项。synchronous_commit=off 可能在崩溃后丢失最近的事务,但数据库仍保持一致。对分析型负载也许可以接受,对支付则不行。修改这些设置前先明确持久性要求。
提交是刷新边界
除非放宽同步提交,否则事务的 WAL 记录必须在客户端收到提交确认前到达持久存储。操作系统页缓存不是持久存储;fsync 才真正把写入落盘。在刷盘前确认提交的数据库,可能在断电后丢失已确认的事务。
组提交可以摊薄成本:多个事务共享一次刷盘。这就是高吞吐数据库每秒能提交大量事务而无需每次提交都刷盘的原因。保证仍然成立:已提交事务在确认前已进入日志。
保留与复制
检查点之后 WAL 段会被复用。副本、归档或复制槽可能要求保留更旧的段。无上限的复制槽或损坏的归档命令会填满磁盘并让主库停止。监控 WAL 生成量、复制槽滞后和归档失败。主库磁盘满是一次故障,不是一条警告。
何时使用
WAL 是存储引擎的实现细节,大多数应用不需要自己实现。在设计备份、复制、崩溃恢复或变更数据捕获时需要理解它。优点是顺序 I/O 下的持久原子提交;缺点是写放大以及围绕保留策略的运维复杂度。