WAL(Write-Ahead Logging,预写式日志)是PostgreSQL实现崩溃恢复、点时间恢复(PITR)以及流复制的核心机制。所有数据修改都会先以日志记录的形式写入WAL文件,然后再落实到数据文件中。很多运维人员在磁盘空间告警时,第一反应是进入pg_wal目录用rm命令删除那些看起来已经很旧的日志文件,这种操作往往会带来灾难性后果。本文将围绕WAL日志的作用机制、手动删除的风险以及安全的清理方案展开详细说明。

一、WAL日志的工作机制与保留策略
WAL日志存放在数据目录下的pg_wal目录中(PostgreSQL 10之前的版本叫pg_xlog),每个WAL段文件默认大小为16MB。数据库在写入数据之前,必须先确保对应的WAL记录已经落盘,这就是所谓的预写式日志。一旦数据库实例发生崩溃,PostgreSQL会在启动时从最近的检查点开始回放WAL日志,将数据库恢复到一致状态。
理解WAL文件的保留逻辑是安全清理的前提。PostgreSQL通过checkpoint机制来决定哪些WAL文件可以被安全删除:每次checkpoint完成后,系统会计算出一个最小恢复点,早于该点的WAL文件在正常情况下不再被需要,数据库会在新的checkpoint触发时自动回收它们。但有两类情况会导致WAL文件被强制保留:一是开启了归档模式(archive_mode为on)且归档命令执行失败,二是存在流复制环境下的复制槽(replication slot)。
如果主库上存在一个已经断开的备用库对应的复制槽,主库会一直保留该备用库所需的全部WAL文件,等待其对端消费。此时pg_wal目录会持续膨胀,这是生产环境中最常见的磁盘占满原因。很多人误以为是日志删除不及时,实际上问题的根源在于复制槽没有得到正确管理。
二、手动删除WAL文件的具体风险
最直接的风险是数据库无法正常启动。PostgreSQL在崩溃恢复时需要从checkpoint点开始顺序回放WAL日志,如果中间某个WAL段文件缺失,恢复过程会中断,数据库实例直接报错停止。常见的错误信息类似PANIC: could not locate a valid checkpoint record或者FATAL: requested WAL segment xxx has already been removed,遇到这种情况往往只能借助pg_resetwal工具强制重置WAL状态,而该操作意味着放弃崩溃恢复,可能造成数据丢失或索引不一致。
第二个风险是破坏归档链的完整性。在开启归档的环境中,PITR恢复要求归档目录中的WAL文件是连续不断的。如果直接删除了尚未归档的WAL段,归档链会从中间断裂,基于时间点的恢复最多只能恢复到断点之前,断点之后的所有变更将永久丢失。对于金融、订单类业务来说,这种数据损失是不可接受的。
第三个风险是导致备用库无法追平主库。流复制的备库依赖主库持续发送WAL数据,如果主库提前删除了备库还没有接收的WAL段,备库会报requested WAL segment has already been removed错误,复制中断。备库只能通过重新做基础备份(basebackup)来恢复,对于大体量数据库来说,这个过程可能耗时数小时,期间的容灾能力形同虚设。
三、安全清理WAL日志的正确方案
首先要排查并处理复制槽问题。可以通过下面的查询查看当前所有复制槽的状态:
-- 查看复制槽及其活动状态
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;
-- 删除已不再需要的废弃复制槽
SELECT pg_drop_replication_slot('slot_name');
如果某个复制槽的active状态为false,但retained_wal的值却在不断增大,说明这是一个僵尸复制槽,它对应的备库已经断开且不再回来,应该及时删除。对于暂时无法判断的场景,可以设置max_slot_wal_keep_size参数(PostgreSQL 13及以上),限制单个复制槽最多能保留的WAL数量,防止磁盘被无限占用。
其次要合理配置checkpoint相关参数。适当增大max_wal_size可以让数据库在两次checkpoint之间缓冲更多WAL文件,减少checkpoint频率,同时系统会自动回收不再需要的旧文件:
# postgresql.conf 中的相关配置 max_wal_size = 4GB # WAL文件总量上限,超过会触发checkpoint min_wal_size = 1GB # WAL文件保留下限 checkpoint_completion_target = 0.9 wal_keep_size = 512MB # 为流复制预留的WAL量
注意一个常见误区:增大max_wal_size本身会增加磁盘占用,它的作用是让回收更平滑,而不是减少总量。如果磁盘确实吃紧,应该反过来评估是否归档链路堵塞才是占用主因。
对于归档场景,正确的做法是让归档命令正常工作,然后在归档端使用pg_archivecleanup工具清理已经归档且早于某个还原点的旧WAL文件:
# 在归档服务器上,基于恢复目标文件清理已归档的WAL pg_archivecleanup /archive_dir/ 000000010000000000000042 # 常见做法:结合restore_command的%r占位符自动清理 restore_command = 'cp /archive_dir/%f %p && pg_archivecleanup /archive_dir/%r'
最后需要强调的是,pg_wal目录内的文件任何时候都不应该用操作系统命令直接删除。如果磁盘已满导致数据库无法写入WAL,可以考虑临时调小wal_keep_size、删除废弃复制槽、修复归档命令等手段让数据库自动回收空间。只有在完全了解后果并接受数据损失的前提下,才由资深DBA评估使用pg_resetwal进行应急处理,且处理后必须立即对数据库做完整的逻辑备份校验。
四、日常运维中的预防措施
建议为pg_wal目录配置独立的磁盘监控告警,阈值设在80%左右,留出足够的响应时间。同时定期巡检pg_stat_archiver视图,确认归档命令的成功率,一旦出现failed_count持续增长,说明归档链路已经异常,WAL文件即将开始堆积。
对于使用流复制的集群,应该建立复制槽的生命周期管理规范,备用库下线时必须同步删除其对应的复制槽,避免僵尸槽长期占用WAL空间。通过以上组合手段,可以在不触碰底层文件的前提下,让WAL空间始终保持在合理范围内,兼顾磁盘利用与数据安全。
PostgreSQL WAL日志手动删除WALpg_wal目录清理修改时间:2026-09-02 13:15:02