PostgreSQL主备复制如何减少WAL文件生成量及优化存储
问题背景
在PostgreSQL主备复制架构中,选定1台备节点作为WAL归档节点,每2小时使用tar命令压缩该备节点上的已归档WAL文件,但存储占用始终居高不下。存储30天、90天周期备份时存在严重存储容量压力,数据恢复过程中下载、重放WAL文件的耗时也很长。
初始已生效配置参数:
wal_level=replica wal_compression=on archive_mode = always
初始未启用的注释参数:
archive_timeout checkpoint_timeout
核心观测现象:通过pg_waldump检测发现WAL内容中70%90%为全页镜像(FPI),在备节点调整参数后仍观测到每分钟生成34个WAL文件,调整后的备节点参数如下:
name | setting | unit --------------------+---------+------ archive_timeout | 0 | s checkpoint_timeout | 3600 | s checkpoint_warning | 3600 | s max_wal_size | 4000 | MB min_wal_size | 2000 | MB shared_buffers | 458752 | 8kB wal_buffers | 4096 | 8kB wal_compression | on | wal_level | replica |
pg_waldump统计示例显示FPI占比达87%:
pg_waldump --stats 0000000100000498000000B2 Type N (%) Record size (%) FPI size (%) Combined size (%) ---- - --- ----------- --- -------- --- ------------- --- XLOG 1 ( 0.00) 114 ( 0.01) 0 ( 0.00) 114 ( 0.00) Transaction 3070 ( 10.35) 104380 ( 4.86) 0 ( 0.00) 104380 ( 0.63) Storage 0 ( 0.00) 0 ( 0.00) 0 ( 0.00) 0 ( 0.00) CLOG 0 ( 0.00) 0 ( 0.00) 0 ( 0.00) 0 ( 0.00) Database 0 ( 0.00) 0 ( 0.00) 0 ( 0.00) 0 ( 0.00) Tablespace 0 ( 0.00) 0 ( 0.00) 0 ( 0.00) 0 ( 0.00) MultiXact 0 ( 0.00) 0 ( 0.00) 0 ( 0.00) 0 ( 0.00) RelMap 0 ( 0.00) 0 ( 0.00) 0 ( 0.00) 0 ( 0.00) Standby 2 ( 0.01) 100 ( 0.00) 0 ( 0.00) 100 ( 0.00) Heap2 590 ( 1.99) 33863 ( 1.58) 46192 ( 0.32) 80055 ( 0.48) Heap 6679 ( 22.51) 578232 ( 26.92) 4482508 ( 30.92) 5060740 ( 30.41) Btree 19330 ( 65.14) 1430918 ( 66.62) 9967524 ( 68.76) 11398442 ( 68.48) Hash 0 ( 0.00) 0 ( 0.00) 0 ( 0.00) 0 ( 0.00) Gin 0 ( 0.00) 0 ( 0.00) 0 ( 0.00) 0 ( 0.00) Gist 0 ( 0.00) 0 ( 0.00) 0 ( 0.00) 0 ( 0.00) Sequence 0 ( 0.00) 0 ( 0.00) 0 ( 0.00) 0 ( 0.00) SPGist 0 ( 0.00) 0 ( 0.00) 0 ( 0.00) 0 ( 0.00) BRIN 0 ( 0.00) 0 ( 0.00) 0 ( 0.00) 0 ( 0.00) CommitTs 4 ( 0.01) 120 ( 0.01) 0 ( 0.00) 120 ( 0.00) ReplicationOrigin 0 ( 0.00) 0 ( 0.00) 0 ( 0.00) 0 ( 0.00) Generic 0 ( 0.00) 0 ( 0.00) 0 ( 0.00) 0 ( 0.00) LogicalMessage 0 ( 0.00) 0 ( 0.00) 0 ( 0.00) 0 ( 0.00) -------- -------- -------- -------- Total 29676 2147727 [12.90%] 14496224 [87.10%] 16643951 [100%]
开启log_checkpoints=on后获取的检查点日志如下:
2022-06-15 07:08:57 UTC [11] LOG: checkpoint starting: time 2022-06-15 07:29:57 UTC [11] LOG: checkpoint complete: wrote 67010 buffers (14.6%); 0 WAL file(s) added, 12 removed, 56 recycled; write=1259.767 s, sync=0.010 s, total=1259.961 s; sync files=253, longest=0.003 s, average=0.001 s; distance=1125728 kB, estimate=2176006 kB 2022-06-15 07:38:57 UTC [11] LOG: checkpoint starting: time 2022-06-15 07:59:57 UTC [11] LOG: checkpoint complete: wrote 61886 buffers (13.5%); 0 WAL file(s) added, 20 removed, 10 recycled; write=1259.740 s, sync=0.005 s, total=1259.878 s; sync files=185, longest=0.002 s, average=0.001 s; distance=491822 kB, estimate=2007588 kB
待解答核心疑问:
- 是否有可行方案减少WAL文件生成量,或易落地的WAL管理方式?
- 仅在备节点修改WAL相关参数是否生效?备节点归档的WAL是主节点发送的原始文件,还是根据备节点自身配置重新生成的?
- 备节点改参数后仍每分钟生成3~4个WAL,是否需要在主节点修改对应参数?主节点配置是否会影响备节点的WAL生成行为?
核心解答
主备WAL生成逻辑说明
- 流复制架构下,备节点接收、归档的WAL完全是主节点生成后通过流复制协议传输的原始WAL流,备节点不会重新生成WAL内容,
checkpoint_timeout、wal_compression、max_wal_size这类控制WAL生成规则的参数在备节点修改对归档WAL无任何效果,所有控制WAL生成量的参数必须在主节点调整才会生效。 - 仅备节点本地恢复触发的检查点、热备反馈产生的少量本地WAL(不会进入归档流程)受备节点参数影响,归档链路的WAL内容、生成速度完全由主节点决定。
WAL高占用、FPI占比过高的根因
FPI(全页镜像)是PostgreSQL的页损坏防护机制:每次检查点之后第一次修改某数据页时,会将整个数据页完整内容写入WAL。你当前环境FPI占比接近9成,核心原因是检查点触发过于频繁——检查点间隔越短,检查点后需要重复写入全页镜像的页数量越多,WAL膨胀越严重。
从提供的检查点日志可以看出,主节点实际检查点间隔仅30分钟,远未达到备节点配置的3600秒,说明主节点要么checkpoint_timeout设置过短,要么max_wal_size阈值太小,WAL量触达阈值后提前触发了检查点。
可落地的WAL减容与管理方案
- 第一优先级:调整主节点参数
- 将主节点
checkpoint_timeout设置为18003600秒(3060分钟,不建议低于30分钟),max_wal_size设置为日常峰值半小时WAL生成量的4~6倍(参考日志中半小时生成约1.1GB WAL的情况,可设为8GB16GB),避免WAL量触顶提前触发检查点,该调整可直接减少30%60%的FPI写入。 - 确认主节点
wal_compression=on(备节点开启该参数无压缩效果,主节点开启后会对WAL中的FPI做压缩,实测可将WAL整体体积压缩至原体积的30%~50%)。 - 保持主节点
archive_timeout=0,不要设置为几十秒的小值,该参数会强制超时切换WAL段,设置过小会产生大量仅写入几KB的无效WAL文件,额外占用存储。
- 将主节点
- 第二优先级:优化归档存储策略
- 替换每2小时打tar包的逻辑,直接在
archive_command中使用高压缩率算法实时压缩WAL,优先选择zstd -19等级压缩,相同压缩率下速度是gzip的35倍,压缩率比gzip高20%30%,既省空间也能避免未压缩WAL临时堆积占满磁盘。 - 做WAL分层存储:30天内需要用于快速恢复的WAL存在高速块存储,30~90天的冷备WAL转存至低成本归档存储,无需长期占用高性能存储容量。
- 替换每2小时打tar包的逻辑,直接在
- 第三优先级:生命周期与进阶优化
- 结合基础备份周期清理过期WAL:无需保留超过「最近2个全量基础备份生成时间+最长恢复窗口」的WAL,比如每周做1次全量基础备份,仅需保留最近2周的WAL即可满足全量恢复需求,更早的WAL可直接删除,无需硬存90天。
- 若业务可接受极端情况下丢失1个检查点周期的数据,且底层存储有可靠的页校验、快照能力,可开启
full_page_writes=off,能直接砍掉80%以上的WAL体积;该参数存在宕机后数据页损坏的风险,无可靠存储保障不建议开启。
常见避坑点
- 不要在备节点调整WAL生成类参数做无用功,所有影响归档WAL的配置均以主节点为准。
- 不要为了“加快检查点速度”将
max_wal_size设置过小,过小的阈值会导致检查点频繁触发,FPI写入量暴增,WAL总占用反而会升高,恢复时WAL重放时间也会更长。 - 不要存储原始未压缩WAL,实时压缩的空间收益远高于定期打包压缩,还能降低磁盘被打满的风险。
内容的提问来源于stack exchange,提问作者Anto
相关产品推荐
相关产品推荐

