PostgreSQL数据目录中的 pg_wal 越来越大,磁盘告警却迟迟不回落,通常不是普通日志轮转失效。WAL承担崩溃恢复、归档和复制,系统只有在确认旧段不再需要后才能回收或复用。
不要直接删除pg_wal中的文件。 正确做法是找出谁在保留WAL,恢复对应的归档或复制消费者,再决定是否调整上限或移除已经废弃的复制槽。

先确认磁盘与WAL增长速度
从系统和数据库两侧采集当前状态:
df -h /var/lib/postgresql
sudo du -sh /var/lib/postgresql/*/main/pg_wal
实际数据目录可通过SQL确认:
SHOW data_directory;
SELECT pg_size_pretty(sum(size)) AS wal_size
FROM pg_ls_waldir();
同时记录5至10分钟内的增长量和磁盘剩余时间。若空间只够支撑很短时间,应先暂停非关键批量写入、扩展磁盘或准备受控停机窗口。先保住数据库可写空间,再进行原因处理。
理解WAL为什么不能随意清理
WAL记录数据页变化,数据库恢复、物理备库、逻辑订阅和时间点恢复都可能依赖它。max_wal_size 是触发检查点和控制常规WAL体量的重要参数,但并不是绝对磁盘硬上限。
复制槽、wal_keep_size、未完成归档和长时间备份都可能要求保留更多WAL。看到超过max_wal_size并不等于参数失效,应继续查实际保留者。
直接删除文件会破坏恢复链,轻则导致备库无法继续,重则让主库重启后无法恢复一致状态。
检查复制槽是否滞后
读取所有槽的活动状态与保留量:
SELECT slot_name,
slot_type,
active,
restart_lsn,
confirmed_flush_lsn,
wal_status,
pg_size_pretty(pg_wal_lsn_diff(pg_current_wal_lsn(), restart_lsn)) AS retained
FROM pg_replication_slots
ORDER BY pg_wal_lsn_diff(pg_current_wal_lsn(), restart_lsn) DESC NULLS LAST;
active=false 且保留量持续增长,通常说明对应备库、CDC或逻辑订阅已停止消费。也要确认槽是否仍属于有效业务,不能看到非活动就删除。
restart_lsn越旧,主库为该槽保留的WAL通常越多。 新版PostgreSQL还可结合 wal_status 判断槽所需文件处于保留、扩展或即将丢失等状态。
核对物理备库与发送进程
在主库查看在线复制连接:
SELECT application_name,
client_addr,
state,
sync_state,
sent_lsn,
write_lsn,
flush_lsn,
replay_lsn,
pg_size_pretty(pg_wal_lsn_diff(pg_current_wal_lsn(), replay_lsn)) AS replay_lag_bytes
FROM pg_stat_replication;
若槽存在但没有对应连接,检查备库服务、网络、证书和连接串。若连接存在但 replay_lsn 长时间不动,应在备库检查磁盘、恢复冲突和PostgreSQL日志。
恢复备库消费比删除槽更安全。 一旦删除仍有用途的物理槽,主库可能回收备库尚未接收的WAL,最终只能重建备库。
检查归档命令是否失败
启用归档时,查询统计信息:
SELECT archived_count,
failed_count,
last_archived_wal,
last_archived_time,
last_failed_wal,
last_failed_time
FROM pg_stat_archiver;
再检查参数:
SHOW archive_mode;
SHOW archive_command;
失败次数增加、最后成功时间停滞,说明归档目标不可写、空间不足、命令权限错误或网络存储异常。修复后应让归档程序继续处理积压,而不是手工把文件从 pg_wal 搬走。
归档是否成功必须以pg_stat_archiver和目标端文件共同确认。 只看到命令返回过0,不能证明后续文件持续可用。
判断是否为写入突增和检查点压力
没有异常槽或归档失败时,检查近期是否发生批量导入、大表更新、索引重建或全量维护。可以观察WAL生成差值:
SELECT pg_current_wal_lsn();
SELECT checkpoints_timed,
checkpoints_req,
checkpoint_write_time,
buffers_checkpoint
FROM pg_stat_bgwriter;
隔一段时间再次读取LSN,使用 pg_wal_lsn_diff() 计算生成量。高写入本身会产生大量WAL,频繁检查点还可能增加I/O压力。
先治理异常写入和任务并发,再考虑扩大参数。 单纯增加磁盘或 max_wal_size 只能延后告警,不能消除失控的消费者。
安全处理已经废弃的复制槽
删除前必须确认槽对应的备库、订阅或CDC任务已经永久下线,并保存槽名、LSN和负责人记录。逻辑复制槽还要确认下游不再需要未消费变更。
确认废弃后执行:
SELECT pg_drop_replication_slot('old_slot_name');
活动槽不能直接删除,应先在消费者侧停止并确认连接释放。删除复制槽是不可逆的保留边界变更,不是临时释放空间按钮。 删除后等待检查点和回收过程,不要期待目录大小瞬间下降。
用上限控制复制槽风险
PostgreSQL提供 max_slot_wal_keep_size,用于限制复制槽在检查点时允许保留的WAL量。默认值 -1 表示槽可能无限保留;设置非负值后,过度滞后的槽可能失去继续复制所需的文件。
SHOW max_slot_wal_keep_size;
这个参数是保护主库磁盘的保险丝,代价是消费者落后过多时需要重建。数值应覆盖可接受的最大断连时间乘以峰值WAL生成速率,并留出缓冲。
在 萤光云 或 LightNode 上搭建同版本短期环境,可以演练槽滞后与重建流程。不要把生产备份、证书或真实业务数据直接复制到测试实例。
空间紧急时的处置顺序
磁盘逼近100%时,先停止造成异常WAL的大批量任务,确认可扩容后在线增加空间,并修复归档或消费者。无法及时扩容时,应评估暂停写入,以避免数据库在不可控时刻失败。
可以清理数据目录之外已确认无关的系统日志或临时文件,但不要触碰 pg_wal、控制文件和数据文件。宁可受控限制写入,也不要用手工删WAL换取几分钟空间。
若主库已经停机,应保留现场并从可验证备份制定恢复方案,不要反复启动和删除文件。
修复后的完整验收
重复查询 pg_replication_slots、pg_stat_replication 和 pg_stat_archiver,确认保留量开始下降、复制LSN持续前进、归档成功时间更新。系统侧确认磁盘空闲量稳定回升。
至少观察一个业务峰值周期,记录每小时WAL生成量、最大槽滞后和归档失败数。验收标准是保留者明确、消费者恢复、增长斜率回归预期,并且告警阈值早于磁盘耗尽时间。
常见问题
可以直接删除pg_wal里最旧的文件吗?
不可以。文件可能仍被崩溃恢复、复制或归档需要,手工删除可能使数据库和备库无法恢复。
max_wal_size为什么限制不住目录大小?
它不是绝对硬上限。复制槽、归档、wal_keep_size 和写入峰值都可能让实际目录更大。
非活动复制槽都能删除吗?
不能。非活动只表示当前没有消费者连接,还需确认该槽已经永久废弃且允许丢失未消费WAL。
温馨提示
任何删除槽或更改WAL保留参数的操作都应先验证备份,并通知备库或CDC负责人。把磁盘剩余时间、WAL增长速度和重建成本一起纳入决策,才能避免从容量故障变成数据恢复事故。


