PostgreSQL WAL 日志归档 + 压缩
一、核心前提:为什么一定要给 WAL 归档做压缩?
✅ 压缩的核心价值(生产环境必做,无任何副作用)
PostgreSQL 的 WAL(Write-Ahead Log)预写日志默认是 16MB / 个的纯二进制文件,未压缩的 WAL 文件冗余度极高:
- 压缩率惊人:常规业务场景压缩率 90%+,16MB 的 WAL 文件压缩后仅 1~2MB;高写入场景压缩率也能达到 70%+,极大节省磁盘空间;
- 节省带宽:如果是远程归档(归档到另一台服务器 / NAS / 对象存储),压缩后传输的数据量大幅减少,避免带宽占满;
- 无性能损耗:压缩是异步归档阶段执行,不会影响数据库的主业务读写性能(WAL 写入是数据库核心流程,压缩在 WAL 文件关闭后执行);
- PG 原生完美支持:压缩后的 WAL 归档文件,在数据库恢复 / 主备同步时,会自动识别并解压,无需手动处理,对恢复逻辑完全透明。
✅ 关键认知
- WAL 日志的归档,核心配置是
archive_command这个参数,WAL 的压缩逻辑,就是直接嵌入在这个归档命令中,无需安装任何插件、无需修改 PG 源码,纯原生实现; - 压缩后的 WAL 文件命名建议保留原文件名 + 压缩后缀(如
.gz/.xz),PG 的恢复机制能自动识别; - 主流压缩方式:
gzip(✅ 99% 场景首选) >xz(极致压缩) >lz4(极速压缩),三者都适配 PG 归档,下面会逐一讲解。
二、前置基础:先开启 PG 的 WAL 归档(必配,压缩的前提)
压缩是基于「归档」的,必须先开启 WAL 归档功能,再在归档命令中加入压缩逻辑,所有配置均在 PG 的数据目录
$PGDATA 下的 postgresql.conf 文件中修改,修改后需要重启 PostgreSQL 服务生效。✅ 1. 核心归档配置(postgresql.conf 必改项)
# ========== 归档核心开关 ==========
# 归档模式开启(必须为on,归档的总开关)
archive_mode = on
# WAL日志级别,归档的最低要求,必须设置为 replica 或 higher (9.6+版本)
wal_level = replica
# ========== 归档命令占位 ==========
# 这里先留空,后面配置「归档+压缩」的完整命令,这是核心配置项
archive_command = ''
# ========== 可选优化配置 ==========
# WAL文件默认大小,默认16MB,无需修改,修改会影响性能
wal_segment_size = 16MB
# 可选:如果长时间无WAL切换(比如只读库),强制多少秒归档一次,避免归档延迟,单位秒
archive_timeout = 60
# WAL写入缓冲区,默认即可,不用改
wal_buffers = 16MB
✅ 2. 重启 PG 服务生效
# CentOS/RHEL/Rocky Linux
systemctl restart postgresql-14 # 替换为你的PG版本
# Debian/Ubuntu
systemctl restart postgresql
# 通用方式
pg_ctl restart -D $PGDATA -m fast
三、方案一:gzip 压缩归档(✅ 首选!生产环境 99% 用这个)
✅ 为什么首选 gzip?
- 压缩 / 解压速度快,CPU 消耗极低,几乎不影响服务器性能;
- 压缩率优秀,16MB 的 WAL 文件压缩后≈1.5MB,压缩率 90%+;
- 系统原生自带,所有 Linux 发行版(CentOS/Ubuntu/Debian)都预装了 gzip,无需额外安装;
- 解压效率远高于 xz,在数据库恢复时,解压速度快能减少恢复耗时,这是生产环境的核心考量。
✅ 配置方式(核心!2 种常用写法,按需选择)
修改
postgresql.conf 中的 archive_command 参数即可,无需重启 PG,执行 pg_ctl reload -D $PGDATA 重载配置生效!✔ 写法 1:【本地归档 + 压缩】最常用,归档到本地目录(推荐)
将 WAL 日志压缩后,归档到本地的指定目录(比如
/pg_archive),必须给 postgres 用户授权该目录的读写权限# 第一步:创建归档目录,postgres用户必须有读写权限(提前执行)
# mkdir -p /pg_archive && chown -R postgres:postgres /pg_archive && chmod 700 /pg_archive
# 核心配置:archive_command 配置gzip压缩+归档
# %p = WAL日志的源文件绝对路径(如 $PGDATA/pg_wal/000000010000000000000001)
# %f = WAL日志的纯文件名(如 000000010000000000000001)
archive_command = 'gzip -6 %p -c > /pg_archive/%f.gz'
命令参数说明
gzip -6:压缩级别,取值 1~9,6 是默认值;1 = 最快压缩(压缩率稍低),9 = 最高压缩率(稍耗 CPU),生产建议用 6 即可;-c:关键参数,stdout标准输出,将压缩后的内容输出到指定文件,而不是替换原文件;> /pg_archive/%f.gz:将压缩后的内容写入归档目录,文件名保留原 WAL 名 +.gz后缀,便于识别。
✔ 写法 2:【归档 + 压缩 + 容错 + 日志】生产最优完整版(强烈推荐!)
上面的基础写法如果归档失败,不会有任何日志,生产环境建议加容错判断 + 日志记录,避免 WAL 归档失败堆积导致磁盘满,同时能排查归档失败原因:
# 归档成功 → 静默;归档失败 → 将错误信息写入日志文件 /pg_archive/archive_fail.log
archive_command = 'gzip -6 %p -c > /pg_archive/%f.gz 2>> /pg_archive/archive_fail.log || echo "归档失败: %f 时间: $(date)" >> /pg_archive/archive_fail.log'
✔ 写法 3:【远程归档 + 压缩】归档到远程服务器(scp 方式,跨机备份)
如果需要将压缩后的 WAL 归档到另一台远程服务器(灾备必备),结合
scp命令即可,前提是配置 postgres 用户的免密 ssh 登录(避免归档时输密码):# 本地压缩后,通过scp上传到远程服务器的归档目录
archive_command = 'gzip -6 %p -c | scp -q -C /dev/stdin postgres@192.168.1.200:/pg_archive/%f.gz'
免密 ssh 配置:在 PG 服务器执行su - postgres→ssh-keygen -t rsa→ssh-copy-id postgres@192.168.1.200
四、方案二:xz 压缩归档(极致压缩,磁盘极度紧张场景)
✅ xz 的特点
- 压缩率比 gzip 更高:16MB 的 WAL 文件压缩后≈800KB,压缩率 95%+,极致节省磁盘空间;
- 缺点:压缩速度比 gzip 慢,CPU 消耗稍高,解压速度也比 gzip 慢;
- 适用场景:磁盘空间非常紧张、WAL 归档量极大、对 CPU 消耗不敏感、对恢复速度要求不高的场景(比如离线备份归档);
- 系统预装:大部分 Linux 发行版自带 xz,若没有则执行
yum install xz -y/apt install xz-utils -y安装。
✅ 配置方式(替换 archive_command 即可)
# 本地xz压缩归档,-6为默认压缩级别,-9为最高压缩率
archive_command = 'xz -6 %p -c > /pg_archive/%f.xz'
# 生产完整版(容错+日志)
archive_command = 'xz -6 %p -c > /pg_archive/%f.xz 2>> /pg_archive/archive_fail.log || echo "归档失败: %f 时间: $(date)" >> /pg_archive/archive_fail.log'
五、方案三:lz4 压缩归档(极速压缩,超高写入性能场景)
✅ lz4 的特点
- 压缩 / 解压速度极快,是三者中速度最快的,CPU 消耗极低,几乎可以忽略不计;
- 压缩率略低于 gzip:16MB 的 WAL 文件压缩后≈3MB,压缩率 80%+;
- 适用场景:高写入性能的核心业务库、对 CPU 和 IO 要求极高、WAL 生成速度极快的场景(比如每秒生成多个 WAL 文件);
- 注意:部分系统默认没有 lz4,需要手动安装:
yum install lz4 -y/apt install lz4 -y。
✅ 配置方式(替换 archive_command 即可)
# 本地lz4压缩归档,-1为默认压缩级别,lz4的压缩级别对速度影响很小
archive_command = 'lz4 -1 %p -c > /pg_archive/%f.lz4'
# 生产完整版(容错+日志)
archive_command = 'lz4 -1 %p -c > /pg_archive/%f.lz4 2>> /pg_archive/archive_fail.log || echo "归档失败: %f 时间: $(date)" >> /pg_archive/archive_fail.log'
六、核心关键:压缩后的 WAL 日志,恢复时是否需要手动解压?
✅ ✔ 答案:完全不需要!PG 原生自动识别 + 自动解压
这是最核心的知识点,也是大家最关心的问题,PostgreSQL 在执行恢复(recovery)时,会自动识别归档的 WAL 文件后缀:
- 如果是
.gz后缀 → 自动调用gunzip解压; - 如果是
.xz后缀 → 自动调用unxz解压; - 如果是
.lz4后缀 → 自动调用lz4 -d解压; - 解压是透明执行的,恢复逻辑和未压缩的 WAL 文件完全一致,无需修改 recovery.conf/recovery.signal 配置,无需任何额外操作。
✅ 恢复的核心原理
PG 的恢复过程中,会读取归档目录中的 WAL 文件,根据文件后缀判断是否为压缩文件,然后调用对应的解压命令将内容读取到内存,再应用 WAL 日志,整个过程对用户无感知。
七、WAL 归档压缩的 生产级优化配置 & 最佳实践(必看,避坑 + 提效)
✅ ✔ 最佳实践 1:归档目录的权限与目录规划
- 归档目录必须给
postgres:postgres属主,权限设置为700,禁止其他用户访问,避免 WAL 文件被篡改:chown -R postgres:postgres /pg_archive chmod 700 /pg_archive - 建议归档目录和 PG 数据目录不在同一个磁盘,避免归档文件占满数据盘导致数据库崩溃;
- 可以按日期分目录归档,便于管理和清理(比如
/pg_archive/202601),适合归档量极大的场景:archive_command = 'mkdir -p /pg_archive/$(date +\%Y\%m) && gzip -6 %p -c > /pg_archive/$(date +\%Y\%m)/%f.gz'注意:date +%Y%m中的%需要转义为\%,因为 PG 的配置文件中%是特殊字符。
✅ ✔ 最佳实践 2:压缩级别的选择(核心调优)
- gzip:生产用
-6(默认)即可,平衡压缩率和速度;如果 CPU 充足,可改为-9(最高压缩);如果 CPU 紧张,改为-1(最快压缩); - xz:建议用
-6,-9 的压缩率提升有限,但 CPU 消耗翻倍; - lz4:固定用
-1,压缩级别对压缩率影响极小,速度优先。
✅ ✔ 最佳实践 3:归档失败的监控与容错(生产必备)
- 上面的归档命令中已经加入了日志记录,建议定期查看
/pg_archive/archive_fail.log日志,排查归档失败原因; - 归档失败的核心后果:WAL 文件会堆积在 $PGDATA/pg_wal 目录,如果长期失败会导致磁盘满,数据库崩溃;
- 监控指标:检查
pg_wal目录的文件数量,如果持续增加,说明归档失败,立即排查。
✅ ✔ 最佳实践 4:归档文件的定期清理(重中之重!)
压缩后的 WAL 文件依然会持续堆积,必须定期清理归档目录的旧 WAL 文件,否则磁盘迟早会满!
- 清理原则:只清理比当前数据库最新 LSN 更早的 WAL 文件,或者根据业务需求保留指定天数(比如保留 7 天归档,足够恢复即可);
- 推荐用 PG 自带的
pg_archivecleanup工具清理,安全无风险,不会误删正在使用的 WAL 文件:# 清理 /pg_archive 目录中,比 000000010000000000000020 更早的WAL文件 pg_archivecleanup /pg_archive 000000010000000000000020 - 生产建议:写一个定时任务(crontab),每天凌晨清理 7 天前的归档文件:
# 编辑postgres用户的定时任务 su - postgres crontab -e # 添加一行:每天凌晨2点清理归档目录中7天前的WAL.gz文件 0 2 * * * find /pg_archive -name "*.gz" -mtime +7 -delete
✅ ✔ 最佳实践 5:避免归档命令阻塞数据库
归档命令是同步执行的,如果归档命令执行缓慢(比如远程 scp 网络卡顿),会阻塞后续的 WAL 归档,导致 WAL 堆积。
解决方案:使用异步归档工具(如
pg_archivewal、wal-g),生产环境高可用建议使用,能极大提升归档的稳定性。八、如何验证 WAL 归档 + 压缩 是否生效?(3 步验证,必做)
配置完成后,必须验证是否生效,避免配置错误导致归档失败,3 个步骤,简单高效:
✔ 步骤 1:重载配置(修改 archive_command 后必做)
pg_ctl reload -D $PGDATA
# 或
systemctl reload postgresql-14
✔ 步骤 2:手动触发 WAL 切换,生成新的 WAL 文件
su - postgres
# 执行切换命令,强制生成新的WAL文件,触发归档
psql -c "SELECT pg_switch_wal();"
✔ 步骤 3:查看归档目录是否有压缩后的 WAL 文件
ls -lh /pg_archive/
✅ 生效的表现:归档目录中出现类似
000000010000000000000001.gz 的文件,文件大小≈1~2MB,说明归档 + 压缩成功!九、常见错误排查(归档压缩失败的高频原因,99% 的坑都在这)
❌ 错误 1:归档目录权限不足 → 最常见!
日志报错:
✅ 解决方案:
permission denied,归档目录的属主不是 postgres,导致无法写入文件。
chown -R postgres:postgres /pg_archive
chmod 700 /pg_archive
❌ 错误 2:压缩命令不存在(比如 lz4 未安装)
日志报错:
✅ 解决方案:
command not found,系统中没有对应的压缩命令。
# gzip
yum install gzip -y
# xz
yum install xz -y
# lz4
yum install lz4 -y
❌ 错误 3:archive_command 配置错误,% p/% f 写反
比如写成
✅ 解决方案:记住固定规则:
gzip %f -c > /pg_archive/%p.gz,% f 是纯文件名,没有路径,会导致找不到文件。
%p = 源文件完整路径,%f = 源文件纯名称,永远是 gzip % p -c > 归档目录 /% f.gz。❌ 错误 4:WAL 文件堆积在 pg_wal 目录,归档目录无文件
说明归档命令执行失败,查看归档失败日志
/pg_archive/archive_fail.log,根据日志信息排查即可。❌ 错误 5:压缩级别写错(比如 gzip -10)
gzip 的压缩级别是 1~9,写 10 会报错,改为 1~9 即可。
十、三种压缩方案的对比 & 生产选型建议(一目了然)
| 压缩方式 | 压缩率 | 压缩速度 | 解压速度 | CPU 消耗 | 适用场景 | 推荐度 |
|---|---|---|---|---|---|---|
| gzip | 90%+ | 快 | 极快 | 极低 | 99% 生产环境、通用场景、主备同步 | ✅✅✅ 强烈推荐 |
| xz | 95%+ | 较慢 | 较慢 | 中等 | 磁盘极度紧张、离线备份、归档量极大 | ✅✅ 可选 |
| lz4 | 80%+ | 极快 | 极快 | 极低 | 高写入性能库、CPU 紧张、极速归档 | ✅✅ 高性能场景首选 |
✅ 最终选型结论
无脑选 gzip 即可,满足 99% 的生产场景需求,平衡压缩率、速度、CPU 消耗,兼容性最好,无任何坑!
浙公网安备 33010602011771号