archive_command写错会导致pitr完全失效:必须满足原子性、幂等性、可监控性,漏判文件存在、路径错误、权限不足或未设archive_timeout=300等均会造成归档中断,使wal链断裂,恢复失败。

archive_command写错会导致PITR完全失效
归档命令不是“能跑通就行”,而是必须满足原子性、幂等性和可监控性。常见错误是直接用cp %p %f,这会因目标文件已存在而失败;或漏掉test ! -f判断,导致重复归档覆盖或cp报错退出——而PostgreSQL只要archive_command返回非0状态码,就会静默停止归档,后续WAL段不再触发归档,时间轴就此断裂。
生产环境应确保:
-
archive_command中%p和%f必须原样使用,不能拼错路径或漏斜杠 - 归档目标目录需由
postgres用户完全控制(chown postgres:postgres /wal_archive) - 命令末尾必须加
&& true或显式返回0,避免shell语法错误导致退出码非0 - 推荐用
rsync -a --ignore-existing %p /wal_archive/%f替代cp,天然支持断点续传和幂等
wal_level和archive_mode必须重启生效
wal_level = replica和archive_mode = on都是静态参数,仅pg_reload_conf()或SIGHUP无法生效,必须重启PostgreSQL服务。很多人改完配置reload就以为开了归档,结果pg_stat_archiver里archived_count始终为0,直到恢复时才发现根本没有WAL可重放。
验证是否真正启用:
- 执行
SELECT pg_is_in_recovery(), current_setting('wal_level'), current_setting('archive_mode');,三者都应返回off、replica、on - 检查进程:重启后
ps aux | grep archive应能看到archiver process子进程 - 手动触发一次WAL切换:
SELECT pg_switch_wal();,然后立刻查/wal_archive/目录是否有新文件生成
archive_timeout是低流量场景的保命参数
默认情况下,WAL段只有写满16MB才会归档。如果数据库负载极低(比如夜间或测试库),可能几小时都不产生新WAL,一旦此时发生误操作,你手头最新归档的WAL可能停留在8小时前——PITR只能回退到那个时间点,中间所有变更全丢。
必须设置archive_timeout = 300(5分钟),强制未满的WAL段定期归档。这个值不是越小越好:
- 设太小(如60秒)会导致大量小WAL段,增加I/O压力和归档存储碎片
- 设太大(如3600)等于放弃对短时间窗口内故障的恢复能力
- 线上建议值:300秒(5分钟)是平衡点,金融类业务可压到180秒
恢复时restore_command路径权限常被忽略
PITR恢复阶段,PostgreSQL以postgres用户身份执行restore_command(如cp /wal_archive/%f "%p")。但很多人在恢复库上只建了归档目录,却忘了给pg_wal/子目录赋权——恢复进程尝试把WAL复制进pg_wal/时因权限不足失败,日志里只报could not restore file,不提示具体原因。
安全做法:
- 恢复前用
sudo -u postgres ls -ld /var/lib/postgresql/*/main/pg_wal确认目录属主是postgres -
restore_command中%p展开后路径必须可写,例如"/var/lib/postgresql/16/main/pg_wal/000000010000000000000001" - 若用
rsync做restore_command,注意--chmod参数确保文件权限正确
最隐蔽的坑是:归档目录和数据目录跨不同文件系统时,cp可能因noexec挂载选项失败,此时必须改用dd if=%p of=%p或明确指定rsync --no-perms。










