min_wal_size 是一个很容易被名字误导的 PostgreSQL 参数。它确实会影响 pg_wal 目录中 WAL 段文件的数量,但它控制的是为后续写入保留多少可回收空间,而不是为备库保留多长时间的历史 WAL。
如果运维人员把它当成备库保护线,就可能在备库长时间断开后发现:所需 WAL 已被回收,流复制无法继续,只能从归档恢复,或者重新制作基础备份。
min_wal_size 保留的是空间,不是历史
PostgreSQL 完成检查点后,会处理已经不再需要的旧 WAL 段。它可以删除这些段,也可以把文件回收并重命名,供未来 WAL 写入复用。
min_wal_size 的作用,是让 PostgreSQL 在 WAL 使用量较低时,仍保留一定规模的可复用段文件。这样下一次写入高峰到来时,数据库不必立即创建大量新文件。
因此,它更接近一个 WAL 文件复用缓存的目标下限:
- 调大后,可以减少负载波动期间反复创建和删除 WAL 文件的频率;
- 调小后,低负载时期可能释放更多
pg_wal空间; - 无论大小,它都不承诺某个旧 LSN 对应的 WAL 一定还在;
- 某段 WAL 一旦不再被其他机制要求保留,就可能被回收并改作未来的 WAL 段。
这里的“回收”不等于“安全保存”。从文件系统角度看,文件可能仍占据磁盘空间;从复制角度看,原先的 WAL 历史已经不存在了。
备库真正依赖哪些机制
备库能否追上主库,取决于它需要的旧 WAL 是否仍可取得。常见保护机制各自解决不同问题。
wal_keep_size:保留一段近期 WAL
wal_keep_size 要求主库在 pg_wal 中保留一定规模的历史 WAL,可用来覆盖短时间的网络中断或备库维护窗口。
它比 min_wal_size 更接近“给备库留一段追赶空间”,但仍应根据 WAL 生成速率计算,而不是随意填写一个看起来足够大的数字。例如,业务高峰每小时产生 20 GB WAL,而维护窗口可能持续 3 小时,那么 8 GB 的设置显然无法覆盖风险。
较老版本的 PostgreSQL 使用 wal_keep_segments;修改前应先确认服务器版本和参数是否存在。
物理复制槽:按备库消费位置保留 WAL
物理复制槽会根据消费者的 restart_lsn 保留所需 WAL。它比固定大小更精确,但代价也很直接:备库长期离线时,WAL 可能持续堆积并占满磁盘。
新版本可通过 max_slot_wal_keep_size 限制复制槽最多占用多少 WAL。这个限制保护了主库磁盘,却也意味着严重落后的复制槽可能失效,因此它不是免费的保险。
WAL 归档:为恢复和长时间中断提供后路
可靠的 WAL 归档把已完成的段复制到独立存储。即使主库已经回收本地 WAL,只要归档完整且备库配置了恢复来源,仍可能从归档继续追赶。
归档系统需要监控失败次数、存储容量和恢复演练。仅仅打开 archive_mode,却不验证归档文件是否真的可读,并不能形成恢复能力。
先检查现状,再修改参数
下面的命令可以直接在 PostgreSQL 主库上执行。它会显示相关参数、当前 pg_wal 大小、流复制延迟和复制槽保留量。运行这些视图和函数通常需要具备相应监控权限;生产环境可使用专门的监控角色。
sudo -u postgres psql -X -d postgres <<'SQL'
SELECT name, setting, unit, context, pending_restart
FROM pg_settings
WHERE name IN (
'min_wal_size',
'max_wal_size',
'wal_keep_size',
'max_slot_wal_keep_size',
'archive_mode',
'archive_command'
)
ORDER BY name;
SELECT pg_size_pretty(COALESCE(sum(size), 0)::bigint) AS pg_wal_size
FROM pg_ls_waldir();
SELECT application_name,
client_addr,
state,
sync_state,
pg_size_pretty(
pg_wal_lsn_diff(pg_current_wal_lsn(), replay_lsn)
) AS replay_lag_bytes
FROM pg_stat_replication;
SELECT slot_name,
slot_type,
active,
restart_lsn,
pg_size_pretty(
pg_wal_lsn_diff(pg_current_wal_lsn(), restart_lsn)
) AS retained_wal
FROM pg_replication_slots
WHERE restart_lsn IS NOT NULL;
SQL
注意,pg_stat_replication 只显示当前连接的复制进程。一个已经断开、且没有复制槽保护的备库不会出现在这里,这正是监控系统不能只看当前连接数的原因。
一个可改造的配置示例
以下数值只是演示配置关系,不是适用于所有数据库的推荐值。实际设置前,应测量高峰期每小时 WAL 生成量、允许的备库中断时间和 pg_wal 所在磁盘容量。
-- 为 WAL 文件复用保留一定空间,主要服务于写入性能和平滑负载波动。
ALTER SYSTEM SET min_wal_size = '2GB';
-- 控制触发检查点时允许的 WAL 增长范围;它是软限制,不是磁盘硬配额。
ALTER SYSTEM SET max_wal_size = '16GB';
-- 示例:为短时间断线的备库保留近期 WAL。
ALTER SYSTEM SET wal_keep_size = '8GB';
-- 示例:限制复制槽导致的 WAL 无限增长。
-- 达到限制后,落后过多的槽可能无法继续使用,因此必须同时告警。
ALTER SYSTEM SET max_slot_wal_keep_size = '32GB';
SELECT pg_reload_conf();
执行后可以确认配置是否生效:
SELECT name, setting, unit, pending_restart
FROM pg_settings
WHERE name IN (
'min_wal_size',
'max_wal_size',
'wal_keep_size',
'max_slot_wal_keep_size'
)
ORDER BY name;
不要仅根据 pg_wal 当前占用量判断参数是否正确。WAL 使用量会受到检查点频率、写入峰值、归档失败、复制槽积压和备库延迟等多种因素影响。
用业务指标计算,而不是凭感觉设值
可以用下面的近似方法估算短暂断线需要的保护空间:
所需 WAL 保留空间 ≈ 高峰 WAL 生成速率 × 最大断线时间 × 安全系数
例如,高峰期 WAL 生成速率为 12 GB/小时,希望覆盖 90 分钟断线,并使用 1.5 的安全系数:
12 GB/小时 × 1.5 小时 × 1.5 = 27 GB
这个结果可以帮助评估 wal_keep_size、复制槽磁盘预算和归档恢复目标,但不能直接替代容量测试。批量导入、创建索引、全表更新等操作可能让 WAL 速率远高于日常平均值。
上线前的检查清单
- 把
min_wal_size当作 WAL 文件复用和性能参数,而不是复制保留策略; - 监控 WAL 每小时生成量,不只监控
pg_wal目录当前大小; - 为短时间断线合理配置
wal_keep_size; - 使用复制槽时监控
restart_lsn、槽是否活跃以及保留字节数; - 为复制槽设置磁盘告警,并理解
max_slot_wal_keep_size可能导致落后槽失效; - 需要覆盖长时间中断时,建设并定期验证 WAL 归档;
- 演练“所需 WAL 已不在主库”时的恢复流程,包括从归档追赶或重建备库。
最关键的判断标准不是“pg_wal 里还有多少文件”,而是“备库需要的那个 LSN 是否仍能从主库、复制槽保护范围或归档中取得”。理解这一区别,才能避免把一项空间复用设置误当成灾难恢复承诺。