27.3 WAL、检查点与写入平滑
写事务的磁盘路径不是“把 table row 写到文件后提交”。
近似链路:
WAL 让 data page 可以延后写,却把 commit latency、checkpoint、archive、replication 和 crash recovery 连接成一个系统。调其中一项,必须看整条链。
27.3.1 WAL 生成、刷盘与提交延迟
write、flush 与 acknowledge
需要区分:
不同 synchronous_commit level 改变 acknowledge 等待的阶段。它不是“开/关性能”:
on:本地 durable,并遵守 synchronous standby 配置;remote_apply:还等待 synchronous standby replay;remote_write:等待 standby 写入 OS;local:等待本地 flush,不等待 synchronous standby;off:允许本地 WAL 尚未 flush 就向 client 确认。
具体 durability 还受 synchronous_standby_names、synchronous_standby_slots、
standby availability 和 application route 影响。不要看到 on 就自动推导
multi-node zero-loss,也不要看到 off 就说“数据会损坏”;它改变的是 crash 时最近
成功确认 transaction 的 loss window。
fsync 与 full_page_writes 不是普通 candidate
可能显著提高 benchmark TPS,但会改变 crash safety。PostgreSQL 官方
WAL settings
明确说明,在可能发生 OS/硬件 crash 的系统中关闭相关保护可能导致不可恢复或静默
损坏。
教学 benchmark 若关闭它们,测的是另一个产品合同。
group commit
多个 backend 可以共享一次 flush:
因此:
- 单 client commit latency 不代表多 client;
- TPS 与 fsync count 不一定 1:1;
- storage fsync tail 比平均 throughput 更重要;
- batch/transaction boundary 改变 group opportunity。
commit_delay/commit_siblings 可以人为等待以扩大 group,但等待本身增加 latency,
只有在高并发、flush 昂贵且实验支持时才考虑。默认不是越大越好。
测 WAL composition
累计层:
PostgreSQL 18 把 WAL I/O bytes/timing 纳入 pg_stat_io;不要照抄旧版本
pg_stat_wal.wal_write_time/wal_sync_time 查询:
列与可用 timing 取决于 PostgreSQL major version 与
track_wal_io_timing。升级时先查 system view schema。
statement 层:
不要公开 query text;用 queryid 对回内部 catalog。
分母要有业务语义
不是同一个指标。
第 26 章 mixed workload 只有 20% place-order,约 158–196 WAL bytes/mixed tx。 不能把它写成“每个订单 196 bytes”。需要按成功 write operation 归一,并把 background activity 与 full-page image phase 作为误差。
WAL buffer full
wal_buffers_full 增加表示 WAL buffer 空间不足时 backend 被迫写 WAL,但不能只看到
counter 就把 wal_buffers 手工调大:
- 默认
-1会基于 shared buffers 自动选择; - upper bound 通常一个 WAL segment;
- 写入/flush device 可能才是限制;
- checkpoint/FPI 或大 transaction 可能改变 burst;
- counter 是累计 delta。
先对齐发生时间与 WAL generation/write/fsync。
commit latency 的证据链
如果 backend 等 SyncRep,加快本地 WAL device 未必改善;如果 server CPU 已饱和,
启用更重 WAL compression 可能反而恶化。
27.3.2 检查点频率、写突发与恢复时间
checkpoint 做什么
checkpoint 建立 recovery 起点,并把需要的 dirty buffer 写出,使 crash recovery 不必从无限久之前 replay WAL。它不是“定期 fsync 一次”这么简单。
触发:
PostgreSQL 18 的证据:
checkpointer 与 bgwriter 已分开统计。关注:
不要用旧版本列名硬编码跨版本 dashboard。
max_wal_size 是 soft limit
它不是:
在 archive failure、replication slot、wal_keep_size、重负载等条件下,WAL 可超过
max_wal_size。把 disk provision 写成 max_wal_size + 10% 是错误模型。
太小的症状
因为每次 checkpoint 后,某页第一次修改需要 full-page image(在保护开启时),过于 频繁会增加 WAL。
太大的代价
增加 max_wal_size/checkpoint_timeout 可能:
- 减少 checkpoint 频率;
- 降低 checkpoint-induced FPI;
- 让 dirty work 有更长时间平滑;
- 增加 crash recovery 要 replay 的 WAL;
- 增加
pg_walworking space; - 延后 dirty page write,扩大 failure/burst 状态;
- 改变 archive/replica catch-up。
优化点不是“checkpoint 越少越好”,而是满足:
checkpoint_completion_target
它控制 checkpoint 在 checkpoint interval 中用于完成的目标比例。默认较高是为了把 I/O 分散到大部分 interval。降低会让 checkpoint 更快完成:
通常不是想要的平滑。参考 Pigsty 沙箱为 0.95;改变它前要看 checkpoint progress、 device latency 与 SLO,而不是复制旧时代 0.7。
写入平滑不是平均值
画 time series:
平均 20MB/s 可能是:
或:
设备和 tail latency 面对的是后者。
恢复时间要实测
粗略:
replay throughput 受:
影响。不能用 WAL device sequential bandwidth 代替。
checkpoint 调整 acceptance 应含 crash/restart 或 replica rebuild drill,而不是只跑 steady primary。
不要为 benchmark 强制 checkpoint
每次 run 前:
会人为同步 phase:
- 一开始 full-page image 更多;
- dirty state 被清空;
- I/O burst 与 production natural phase 不同。
如果研究 checkpoint phase,应把 “immediately after checkpoint / mid-cycle” 作为显式 factor;否则让背景系统自然运行并记录 checkpoint。
27.3.3 压缩、全页写与归档代价
full-page image 的正确性作用
当 full_page_writes=on,checkpoint 后某页第一次被修改时,WAL 通常记录整页 image,
以防 torn page 让 recovery 无法还原。于是:
但关系受 working set 与 write locality 影响。修改同一小批 hot page 与随机修改巨大 dataset 的 FPI 比例不同。
wal_compression
PostgreSQL 18 支持的 method 取决于 build:
它主要压缩 full-page image,不是压缩所有 WAL record。tradeoff:
参考沙箱:
第 26 章 c8 已有 CPU pressure,却没有证明 WAL I/O 是 throughput limit。因此“开启更强 compression 减少 WAL”不符合当前 service center evidence。
compression 实验矩阵
至少比较:
| 维度 | 指标 |
|---|---|
| primary | TPS、p95、CPU、wal_bytes、wal_fpi |
| WAL device | write/fsync bytes/latency |
| network/archive | bytes/s、backlog、catch-up |
| replica | replay CPU、lag、recovery |
| backup/PITR | archive compatibility、restore time |
| failure | crash replay、promotion |
只看 wal_bytes 降低不能决定接受。
archive 与 slot 可能让 WAL 无界
若 archive throughput $A$ 小于 WAL generation $W$:
$$ \text{backlog growth}
W-A $$
增加 max_wal_size 只推迟 disk full,不修复 consumer。
若 slot inactive:
列随版本变化,先查当前 view。还要配置/验证 max_slot_wal_keep_size 等 guard,但 guard
触发可能使 consumer 无法继续,属于 recovery/runbook 决策。
min_wal_size 与 recycle
min_wal_size 让一定量旧 WAL segment 被 recycle 供未来使用,减少 burst 时反复创建/
删除。它不是最小 WAL generation,也不是 retention policy。
filesystem 类型可能影响:
尤其 CoW filesystem。但这些是 storage-specific candidate,应以文件系统、allocation 行为和 crash test 证明,不能把云盘经验搬到本地 SSD。
归档压缩与 WAL compression 是两层
二者可叠加,CPU 消耗发生在不同进程/节点/阶段。容量模型要测最终 archive object
bytes 和两侧 CPU,不要把 primary wal_bytes ratio 当作备份压缩率。
参数 ADR
WAL/checkpoint 变更应写:
没有 recovery/retention 证据的 checkpoint 优化,只完成了一半。
上一节:内存预算 · 返回本章目录 · 下一节:规划器、并行与连接参数 · 查看全书目录 · 查看索引中心