在 PostgreSQL 流复制环境中,主库需要保留一定量的 WAL 文件,以便备库断开连接后重新建立复制时能够获取缺失的日志。长期以来,wal_keep_segments 承担这一职责,它接受一个整数值,表示 pg_wal 目录中至少保留的 WAL 段数量。但从 PostgreSQL 13 开始,这个参数被正式标记为废弃,并被 wal_keep_size 取代。二者并非简单的重命名,而是计量模型的改变。理解这一变化的内部逻辑,对升级和日常运维都有实际价值。

参数演进:为什么从段数走向字节数
wal_keep_segments 的定义一直围绕 WAL 段数量展开。WAL 段是 PostgreSQL 中预写日志的物理存储单元,默认大小为 16MB,但这个值在编译数据库时可以通过 --with-wal-segsize 参数调整,可选范围通常为 1MB 到 1024MB。因此,同样设置 wal_keep_segments = 64,在默认段大小为 16MB 的实例上保留约 1GB 日志,而在段大小为 64MB 的实例上则会保留 4GB。这种隐藏的差异给容量评估带来不确定性,尤其在混合部署环境中,运维人员容易误判磁盘占用。
改为 wal_keep_size 之后,参数直接表达需要保留的 WAL 总字节数,单位统一为 MB。它不关心底层 WAL 段是 16MB 还是 64MB,只要计算出需要保留多少 MB 即可。对于磁盘规划和监控来说,这种表达方式更符合直觉。例如,你希望主库在备库掉线后还能保留最近 2GB 的 WAL,直接设置 wal_keep_size = 2048 或 wal_keep_size = '2GB',而不必先换算出 128 个段。当段大小在未来发生变化时,配置值也不需要重新计算。
这一调整也反映了 PostgreSQL 在复制与高可用场景下对配置友好性的持续改进。旧的段数模型诞生于流复制早期,当时 WAL 段大小既定且默认值普及,后来随着可调段大小的部署增多,字节数便成为更通用的度量方式。从代码演进角度看,把 wal_keep_segments 标记为废弃并引入 wal_keep_size,也是为了降低新用户的理解门槛,同时为后续版本移除旧参数铺平道路。
wal_keep_size 的配置与换算
wal_keep_size 是一个整型参数,默认值为 0,单位是 MB。可以在 postgresql.conf 中直接写入:
wal_keep_size = 512MB
也可以使用 ALTER SYSTEM 命令动态修改并持久化到 postgresql.auto.conf:
ALTER SYSTEM SET wal_keep_size = '512MB'; SELECT pg_reload_conf();
如果仍保留旧参数 wal_keep_segments,在 PostgreSQL 13 中系统会接受它,但会按当前 WAL 段大小自动换算成 wal_keep_size,并在启动或重载日志中输出类似 wal_keep_segments is deprecated 的警告。例如,假设 WAL 段大小为 16MB,旧的 wal_keep_segments = 64 就等价于 wal_keep_size = 1024MB。反过来,如果希望保留 256 个默认段,可以设置 wal_keep_size = 4096MB。实际查询当前 WAL 段大小可以使用以下语句:
SELECT name, setting, unit
FROM pg_settings
WHERE name IN ('wal_segment_size', 'wal_keep_size');
wal_segment_size 返回以字节为单位的整数值,例如 16777216 对应 16MB。通过 current_setting 函数也能获取当前配置:
SELECT current_setting('wal_segment_size') AS segment_bytes,
current_setting('wal_keep_size') AS keep_size_mb;
需要注意的是,wal_keep_size 的值并不会因为设置了 wal_keep_segments 而自动出现在 pg_settings 视图中。PostgreSQL 是在启动时将旧参数值转换为内部等效字节数,对应用户看到的 wal_keep_size 可能并非实际生效值。要确定最终生效的保留量,建议在升级后显式移除旧参数,只用 wal_keep_size 一项来配置。
升级兼容与常见问题
从 13 升级到 14 及以上版本时,wal_keep_segments 参数会被彻底移除。如果 postgresql.conf 或 postgresql.auto.conf 中仍然包含该参数,数据库可能拒绝启动并报错 unrecognized configuration parameter wal_keep_segments。因此,在执行 pg_upgrade 或大版本升级前,需要先检查并替换配置文件中的旧参数。一个快速检查命令是:
grep -r "wal_keep_segments" /etc/postgresql/14/main/
找到相关行后,将其替换为 wal_keep_size,并按前文公式换算。例如原配置 wal_keep_segments = 32,在 16MB 段大小下改为 wal_keep_size = 512MB。改完后执行 pg_ctl reload 加载新配置,并用 SHOW wal_keep_size 验证。
另一个常见问题是 wal_keep_size 与复制槽同时存在时的行为。复制槽会强制主库保留所有尚未被备库消费的 WAL,而 wal_keep_size 只是额外的基础保留量。如果备库长期宕机,复制槽可能导致主库 WAL 无限增长,直到磁盘耗尽。因此,在高可用架构中通常会搭配 max_slot_wal_keep_size 来限制复制槽的保留上限。此时 wal_keep_size 仍独立生效,它保证即使没有复制槽或复制槽已被删除,pg_wal 目录也至少保留指定大小的日志,便于重新建立复制关系。
还有用户会在升级后遇到同时设置 wal_keep_size 和 wal_keep_segments 的情况。在 PostgreSQL 13 中,如果两者同时出现且 wal_keep_size 显式设置,新参数优先,旧参数被忽略;如果只设置旧参数,则使用换算值。但从 14 开始,旧参数会直接导致错误,所以不建议同时保留两个参数,应尽早清理。
容量规划与监控建议
合理的 wal_keep_size 取决于两个关键指标:WAL 生成速率和备库允许的最大离线时间。WAL 生成速率可以通过查询 pg_stat_wal 或比较 pg_current_wal_lsn 在不同时间点的位置得到。例如,记录当前 LSN,等待 10 分钟再记录一次,计算差值就是这段时间产生的 WAL 字节数。按此速度乘以可容忍的离线小时数,就能得出基础保留量。一般建议设置至少能覆盖一次完整的备份或网络分区恢复周期,例如 2 到 4 小时。
可以通过 pg_ls_waldir 函数查看当前 pg_wal 目录中文件大小和数量,评估参数是否生效:
SELECT count(*) AS walfile_count,
pg_size_pretty(sum(size)) AS total_size
FROM pg_ls_waldir();
监控时还应关注 pg_stat_replication 中的 write_lag、flush_lag 和 replay_lag,这些字段反映备库落后主库的时间。如果备库已经掉线,这些值会停止更新,此时主库的 WAL 保留只能依赖 wal_keep_size 或复制槽。一旦保留不足,备库重新连接后会报 requested WAL segment has already been removed 错误,此时只能重新做基础备份。
最后需要明确,wal_keep_size 只负责保留 pg_wal 目录中的在线 WAL 文件,不负责归档。如果同时配置了 archive_command,归档的 WAL 会转存到其他位置,wal_keep_size 的值可以相应降低。获取共享存储或对象存储上的归档后,主库不需要长期保留本地 WAL,从而减少本地磁盘压力。但归档不可用时,wal_keep_size 就是保住复制连续性的最后一道防线,所以不能设为过小值。
PostgreSQLwal_keep_sizewal_keep_segments修改时间:2026-10-04 13:02:10