Skip to content

恢复配置(restore_command / recovery_target) ​

"恢复配置"指的是:当我们已经准备好一份基础备份、并且归档里有连续的 WAL 时,如何告诉 PostgreSQL "把 WAL 从哪里取来、重放到哪里停、停下来之后做什么"。这三件事分别由 restore_command、recovery_target_* 和 recovery_target_action 决定。

从 PostgreSQL 12 开始,这些参数不再写在独立的 recovery.conf 里,而是写在常规配置文件中(postgresql.conf 或 postgresql.auto.conf),并通过在数据目录中放置一个信号文件来触发恢复模式。这是版本演进中变化最大的一处,也是很多老教程给出错误做法的根源——本页会先把这一点讲清楚,再逐项展开其他参数。

需要强调的一点是:恢复配置是"事后"的、临时的配置。它只在一次恢复过程中有意义,恢复完成后通常会被清理掉(例如删除信号文件)。因此不要把它当成长期配置写进 postgresql.conf 的主配置区,更合适的做法是在恢复时临时追加、恢复完成后移除,避免下次意外启动又进入恢复模式。

基础概念 ​

恢复配置的承载方式变迁 ​

版本恢复参数写在哪触发方式
PostgreSQL 11 及更早数据目录下的 recovery.conf该文件存在即进入恢复;处理后被改名为 recovery.done
PostgreSQL 12 及以后postgresql.conf / postgresql.auto.conf数据目录下存在 recovery.signal 或 standby.signal

关键结论:recovery.conf 在 PostgreSQL 12 已被彻底移除。官方明确说明:如果数据目录中存在 recovery.conf,服务端将拒绝启动。因此按老教程创建 recovery.conf 不仅不会生效,还会直接导致实例起不来。正确做法是把参数写进配置文件,再 touch recovery.signal。

同一份官方说明里还提到两个相关的移除项:standby_mode 参数被移除,改由 standby.signal 文件表达;更早的 trigger_file / promote_trigger_file(PostgreSQL 15 及更早版本存在)也被移除,提升改为使用 pg_ctl promote 或 pg_promote()。

两个信号文件 ​

信号文件语义恢复完成后
recovery.signal这次是"有终点的恢复"(PITR)到达目标后按 recovery_target_action 处理
standby.signal这次是"持续恢复"(备库),没有终点永不主动停止,持续等待新 WAL

两者互斥,同时存在会导致启动失败。区别只在"重放是否会停":

  • 有 recovery.signal:重放到 recovery_target 命中的位置后停止,或重放到 WAL 末尾后停止。
  • 有 standby.signal:一直重放,等待 restore_command 或 primary_conninfo 提供更多 WAL。

因此,如果只是想搭一个备库,用 standby.signal;如果要把库恢复到过去某个时间点,用 recovery.signal。

恢复相关参数总览 ​

参数作用生效方式
restore_command从归档取 WAL 的命令reload / 启动时
archive_cleanup_command清理不再需要的归档文件reload / 启动时
recovery_end_command恢复结束时执行一次的命令reload / 启动时
recovery_target特殊值 immediate,到达一致点即停启动时
recovery_target_name按命名还原点停止启动时
recovery_target_time按时间戳停止启动时
recovery_target_xid按事务 ID 停止启动时
recovery_target_lsn按 WAL 位置停止启动时
recovery_target_inclusive是否包含恰好命中的记录启动时
recovery_target_timeline跟随哪条时间线启动时
recovery_target_action到达目标后的动作启动时
recovery_min_apply_delay延迟重放(用于备库)reload / 启动时

注意"启动时生效"这一类:它们只在恢复启动阶段读取,恢复过程中修改没有意义。

restore_command ​

restore_command 是一个 shell 命令,用来从归档位置取回一个 WAL 文件。它支持与 archive_command 相同的占位符:

占位符含义
%f要恢复的 WAL 段文件名
%p恢复目标的完整路径(注意与 archive_command 的 %p 语义不同)
%%一个字面量百分号

这条命令的失败语义非常重要:找不到文件时应当立即返回非 0,不要等待、不要重试、不要阻塞。服务端会在需要时再次调用它。如果命令内部做了长时间等待(例如等网络挂载点恢复),恢复进程会被白白拖住。

recovery_target 系列 ​

recovery_target 是一个"特殊值"参数,只有一个合法取值 immediate;它的同族参数才是真正的目标指定方式。这组参数只能设置一个(immediate 与其他目标类型互斥),设置多个非 immediate 的目标,服务端会报错。

参数停止条件典型用途
recovery_target到达一致点立即停止只想要"能启动的最小状态"
recovery_target_name命中指定还原点事前打过还原点的场景
recovery_target_time重放到指定时间戳已知误操作时间的场景
recovery_target_xid重放到指定事务已知事务 ID 的场景
recovery_target_lsn重放到指定 WAL 位置最精确的场景

recovery_target_action ​

这个参数决定"到达目标之后做什么",取值三个:

取值行为说明
pause暂停在目标点,等待人工决定默认值,最安全
promote立即提升为可写主库自动化恢复常用
shutdown停止服务用于"先恢复出数据、暂不对外提供"的场景

特别要注意默认值是 pause:如果没设置 recovery_target_action,恢复到达目标后会暂停,实例可以接受只读查询,但不会自动变成可写状态。这与很多人"恢复完自动变主库"的预期不同。

recovery_min_apply_delay ​

这个参数让备库在重放 WAL 时人为延迟一段时间再应用。它不是给 PITR 用的,而是给备库用的(需要配合 standby.signal)。

它的典型价值是:当主库发生误操作时,备库因为延迟,还没有执行这条误操作的 WAL,运维可以在延迟窗口内把备库提升,从而"顺便"完成一次快速恢复。

代价是:

  • 备库的数据天然落后一段时间(这是设计意图);
  • 只有"提交时间戳"到达之后才会应用(延迟的度量基于 WAL 记录里的时间戳);
  • 延迟会传播到下游备库(级联复制时);
  • 大幅延迟的备库在切换时会损失对应时间的数据。

语法与用法 ​

最简恢复配置 ​

conf
# postgresql.conf 追加(或写入 postgresql.auto.conf)

# 从归档取 WAL
restore_command = 'cp /mnt/wal_archive/%f %p'

# 恢复到某个时间点
recovery_target_time = '2026-09-20 10:30:00+08'

# 到达目标后提升为可写主库
recovery_target_action = 'promote'
bash
# 在数据目录中放置恢复信号文件
touch $PGDATA/recovery.signal

恢复过程的日志 ​

text
LOG:  starting point-in-time recovery to 2026-09-20 10:30:00+08
LOG:  restored log file "0000000100000000000000B2" from archive
LOG:  redo starts at 0/16000028
LOG:  consistent recovery state reached at 0/16B3748
LOG:  recovery stopping before commit of transaction 743, time 2026-09-20 10:31:12.339251+08
LOG:  redo done at 0/16C4D00
LOG:  selected new timeline ID: 3
LOG:  archive recovery complete

检查当前是否处于恢复状态 ​

sql
-- 返回 true 表示当前仍在恢复(或处于备库模式)
SELECT pg_is_in_recovery();
text
 pg_is_in_recovery
-------------------
 f
(1 row)
sql
-- 恢复进度相关(在恢复中才有意义)
SELECT pg_last_wal_receive_lsn()  AS received,
       pg_last_wal_replay_lsn()   AS replayed,
       pg_last_xact_replay_timestamp() AS last_replay_time;
text
  received   |  replayed  |     last_replay_time
-------------+------------+---------------------------
 0/16C4D00   | 0/16C4D00  | 2026-09-20 10:31:12.339+08
(1 row)

手工提升 ​

sql
-- 如果 recovery_target_action = 'pause',可手工提升
SELECT pg_promote();
text
 pg_promote
------------
 t
(1 row)
sql
-- 带等待与超时的写法(wait 为 true 时等待完成,timeout 单位为秒)
SELECT pg_promote(true, 60);

详细说明 ​

为什么弃用 recovery.conf ​

recovery.conf 的设计有一个明显的缺陷:它是"数据目录下的一个文件",而"文件是否存在"同时承担了"参数容器"和"是否恢复"两个职责。这带来几个问题:

  1. 配置文件分裂。一个实例的配置分散在 postgresql.conf、postgresql.auto.conf、recovery.conf 三处,ALTER SYSTEM 无法统管,排查配置来源困难。
  2. 状态难表达。恢复完成后文件被改名,但这个"改名的动作"本身不是事务性的,异常中断时状态可能不清晰。
  3. 与备库概念纠缠。备库本质上就是"永不停止的恢复",但 recovery.conf 的名字暗示它是一个"一次性恢复"。

PostgreSQL 12 的改法是把"参数"归入常规配置文件(从而被 ALTER SYSTEM、统一配置管理覆盖),把"是否恢复"单独交给信号文件表达。这个划分更清晰,也让恢复参数可以被工具(如 pg_basebackup 的 -R)以标准方式写入。

信号文件的创建位置与内容 ​

信号文件位于数据目录根部,内容是空的(只起标记作用):

bash
# 数据目录中应该看到的样子
ls -la $PGDATA/*.signal
text
-rw-r--r-- 1 postgres postgres 0 Sep 28 10:20 /var/lib/postgresql/18/main/recovery.signal

注意几点:

  • 文件必须是空文件,内容会被忽略;
  • 权限需要让 PostgreSQL 运行用户可读;
  • 恢复完成(提升)后,服务端会自动删除 recovery.signal,避免下次启动又进入恢复;
  • standby.signal 在提升时也会被自动删除。

restore_command 的占位符 ​

restore_command 的占位符与 archive_command 有一处关键差异:%p 在恢复时指向恢复目标的完整路径(即要把 WAL 写到哪),而 %f 是要恢复的文件名。因此命令通常是"从归档取到 %p":

bash
# 从本地归档目录取
restore_command = 'cp /mnt/wal_archive/%f %p'

# 以"不存在则失败"的方式取(推荐:找不到就立即返回非 0)
restore_command = 'test ! -f /mnt/wal_archive/%f && exit 1; cp /mnt/wal_archive/%f %p'

# 支持压缩归档(先解压再写入)
restore_command = 'gunzip -c /mnt/wal_archive/%f.gz > %p'

# 从对象存储拉取
restore_command = 'aws s3 cp s3://wal-bucket/%f %p'

# 从远端主机拉取,带超时避免挂起
restore_command = 'timeout 30 scp archive@host:/wal/%f %p'

压缩归档是一个很实用的技巧:把 WAL 用 gzip 压缩后归档,恢复时解压,可以显著减少归档存储占用。代价是归档时需要额外一步(例如在归档脚本里压缩),且 restore_command 要对应处理。

停止位置的语义细节 ​

recovery_target_* 决定"在哪里停",但"停"的精确语义还受 recovery_target_inclusive 影响。

目标类型默认 inclusive = true 的含义inclusive = false 的含义
recovery_target_time重放所有提交时间 ≤ 目标的记录只重放提交时间 < 目标的记录
recovery_target_xid包含指定事务本身不包含指定事务
recovery_target_lsn包含到达该 LSN 的记录不包含到达该 LSN 的记录
recovery_target_name包含还原点记录—(对命名还原点通常保持默认)

还有一个必须知道的特例:recovery_target_xid 按"事务 ID 分配顺序"而非"提交顺序"来停止。事务 ID 只是发起顺序,提交顺序可能不同。因此 recovery_target_xid 在某些情况下可能停止在一个与直觉不一致的位置——它会在"所有 XID 小于目标的记录都已重放"处停止,即使那些事务的提交时间晚于目标。这一点让 recovery_target_xid 的实用性不如 recovery_target_time 和 recovery_target_lsn。

多个目标参数如何处理 ​

如果同时设置了多个目标参数,服务端会报错并拒绝启动。这是有意的设计,避免"以为按时间停、实际按 LSN 停"这类歧义。

但有一个例外组合是可以的:recovery_target(immediate)与 recovery_target_action。因为前者是"不指定具体目标",后者是"到达后做什么",二者不冲突。

recovery_target_action 的三个取值详解 ​

取值到达目标后对连接的影响适用场景
pause停在目标点可接受只读连接需要人工核对数据后再决定
promote提升为可写可接受读写连接自动化恢复脚本
shutdown关闭实例连接被断开只想"恢复出文件",稍后再启动

shutdown 的典型用法:需要把恢复出来的数据用文件系统工具检查、或者需要先复制某些文件出来时,让实例保持关闭状态比让它以只读方式开放更省事。

pause 状态下如何继续,有三种方式:

sql
-- 方式一:提升为可写主库(最常用)
SELECT pg_promote();
bash
# 方式二:告诉服务端继续重放到下一个目标(需要重新配置目标)
#   实际操作是:停止服务 → 修改 recovery_target_* → 重启

# 方式三:直接提升(等价于 pg_promote,需要服务在 pause 状态)
pg_ctl promote -D $PGDATA

pg_ctl promote 与 pg_promote() 都能完成提升,区别是前者是外部命令(不需要数据库连接),后者需要能连上实例。

archive_cleanup_command ​

恢复过程中会不断从归档取 WAL。已经不再需要的归档文件可以由 archive_cleanup_command 清理,官方配套的工具是 pg_archivecleanup:

conf
archive_cleanup_command = 'pg_archivecleanup /mnt/wal_archive %r'

%r 是"当前恢复所需的起始 WAL 文件",pg_archivecleanup 会删除归档目录中早于该文件的所有 WAL 段。

这个参数主要用于备库:备库长期运行,归档目录如果无人清理会无限增长。但要注意风险:

  • 如果还有其他实例(或其他恢复目标)依赖更早的归档,清理会破坏它们的恢复能力;
  • 删除是不可逆的,应确保归档另有异地备份。

因此在"多实例共享归档目录"或"需要保留历史恢复点"的场景下,不要启用自动清理,而是用独立的保留策略脚本统一管理。

recovery_end_command ​

recovery_end_command 在恢复完成时执行一次,常用于做通知、标记:

conf
recovery_end_command = 'touch /var/lib/postgresql/recovery_finished_$(date +%F_%H%M%S)'

它的作用域很窄(只执行一次),且如果它失败会记录警告,但不影响恢复结果。因此适合做"打点",不适合做"必须成功的业务动作"。

recovery_min_apply_delay ​

这个参数的单位是毫秒(也接受带单位的时间写法)。它让备库延迟应用 WAL:

conf
# 备库延迟 30 分钟应用
recovery_min_apply_delay = '30min'

语义细节:

  • 延迟针对的是提交时间戳,即"从 WAL 记录里的提交时间算起,至少过 30 分钟才应用";
  • 如果主库和备库的系统时钟差异很大,延迟行为会受影响;
  • 只有"可重放的提交"(有提交时间戳的记录)会被延迟,其他记录不受影响;
  • 延迟会级联:如果备库 B 从备库 A 拉 WAL,A 的延迟会叠加到 B 上。

一个重要的判断:延迟备库不是备份的替代品。它只能对抗"发现得很快"的误操作,一旦误操作在延迟窗口之后才被发现,备库也已经应用了。真正的兜底仍然是"基础备份 + WAL 归档"的 PITR。

从备份目录启动恢复的完整参数组合 ​

把恢复所需的参数集中列出来,形成一个可直接使用的模板:

conf
# --- 恢复参数(仅恢复期间需要)---

# 1. WAL 来源
restore_command = 'cp /mnt/wal_archive/%f %p'

# 2. 恢复目标(四选一;或用 recovery_target = 'immediate')
recovery_target_time = '2026-09-20 10:30:00+08'

# 3. 边界是否包含命中的记录
recovery_target_inclusive = on

# 4. 跟随的时间线(默认 latest)
recovery_target_timeline = 'latest'

# 5. 到达目标后的动作
recovery_target_action = 'promote'

# 6. 归档清理(可选,谨慎使用)
# archive_cleanup_command = 'pg_archivecleanup /mnt/wal_archive %r'

# 7. 恢复结束命令(可选)
# recovery_end_command = 'echo recovery done'
bash
# 启动前确认两件事:
#   1) 数据目录里没有 standby.signal(它会让实例变成"永不停止的备库")
#   2) 数据目录里有 recovery.signal
ls -la $PGDATA/*.signal 2>/dev/null
touch $PGDATA/recovery.signal

恢复失败时的常见错误 ​

日志 / 现象原因处理
could not find WAL file 反复出现并最终失败归档缺段或 restore_command 路径错检查归档连续性、占位符
recovery ended before configured recovery target was reached目标超出 WAL 覆盖范围修正目标,或补齐 WAL
invalid checkpoint record / 启动即失败基础备份不完整或版本不匹配重新获取基础备份
recovery_target_time is before the last checkpoint目标早于基础备份起点目标不可达,需更早的备份
一直停在 pause,服务只读recovery_target_action 为默认 pause设为 promote 或手工 pg_promote()
服务无法启动,提示信号文件冲突同时存在 recovery.signal 与 standby.signal只保留一个

上表中前两类错误最值得提前理解:"目标超出 WAL 覆盖范围"和"目标早于备份起点"是恢复目标选择的两个硬边界——可达的恢复区间是 [基础备份起点, 已归档 WAL 末尾]。

实战示例 ​

示例一:恢复到时间点(最典型流程) ​

bash
# 1. 停止服务
sudo systemctl stop postgresql-18

# 2. 保全现场(改名而不是删除)
mv $PGDATA $PGDATA.old_20260928
mkdir -p $PGDATA
chmod 0700 $PGDATA
chown postgres:postgres $PGDATA

# 3. 展开基础备份到数据目录
tar -xzf /backup/base_20260928.tar.gz -C $PGDATA
# 注意:tar 包内的目录结构可能需要调整,确保 PG_VERSION 直接位于 $PGDATA 下

# 4. 写入恢复参数
cat >> $PGDATA/postgresql.auto.conf <<'EOF'
restore_command = 'cp /mnt/wal_archive/%f %p'
recovery_target_time = '2026-09-20 10:30:00+08'
recovery_target_action = 'promote'
EOF

# 5. 创建恢复信号文件
touch $PGDATA/recovery.signal

# 6. 修正属主与权限
chown -R postgres:postgres $PGDATA
chmod 0700 $PGDATA

# 7. 启动并观察日志
sudo systemctl start postgresql-18
sudo tail -f /var/log/postgresql/postgresql-18-main.log
sql
-- 8. 验证:确认已提升(返回 f)、确认目标时刻的数据状态
SELECT pg_is_in_recovery();

SELECT count(*) FROM orders WHERE created_at > '2026-09-20 10:30:00+08';

示例二:使用命名还原点恢复 ​

sql
-- 事前:在关键操作前打还原点
SELECT pg_create_restore_point('before_price_adjust_20260928');
text
   pg_create_restore_point
--------------------------
 0/1B2C340
(1 row)
conf
# 恢复时的配置
restore_command = 'cp /mnt/wal_archive/%f %p'
recovery_target_name = 'before_price_adjust_20260928'
recovery_target_action = 'promote'

命名还原点的优势是"不依赖时钟、不依赖人回忆时间"——目标的语义由业务动作定义,最不容易出错。

示例三:按 LSN 精确恢复 ​

先从 WAL 里找出目标位置。pg_waldump 可以读 WAL 内容:

bash
pg_waldump -p /mnt/wal_archive 0000000100000000000000B3 | grep -i 'DELETE'
text
rmgr: Heap        len (rec/tot):     59/    59, tx:        743, lsn: 0/16C4D00, prev 0/16C4CC8, desc: DELETE off 5 flags 0x00 KEYS_UPDATED , blkref #0: rel 1663/16384/24576 blk 12

注意到错的删除事务的 LSN 是 0/16C4D00,于是把目标设在该位置之前:

conf
restore_command = 'cp /mnt/wal_archive/%f %p'
recovery_target_lsn = '0/16C4D00'
recovery_target_inclusive = off   # 不包含该条记录
recovery_target_action = 'promote'

这是精度最高的恢复方式:不受时间戳精度、时钟偏移的影响。

示例四:配置延迟备库 ​

conf
# 备库(有 standby.signal)的配置
# 主库信息
primary_conninfo = 'host=10.0.1.10 port=5432 user=replicator application_name=standby1'

# 延迟 30 分钟应用
recovery_min_apply_delay = '30min'
sql
-- 在备库上观察延迟(received 应明显领先 replayed)
SELECT pg_last_wal_receive_lsn() AS received,
       pg_last_wal_replay_lsn()  AS replayed,
       pg_wal_lsn_diff(pg_last_wal_receive_lsn(), pg_last_wal_replay_lsn()) AS lag_bytes,
       now() - pg_last_xact_replay_timestamp() AS lag_time
FROM pg_stat_replication
LIMIT 1;
text
  received  |  replayed  | lag_bytes |    lag_time
------------+------------+-----------+----------------
 0/1B2C340  | 0/1B2B000  |     4792  | 00:29:52.113
(1 row)

lag_time 稳定在接近 30 分钟,说明延迟生效。

示例五:从 pause 状态决定继续或放弃 ​

sql
-- 恢复到达目标,处于 pause 状态,先做只读核对
SELECT pg_is_in_recovery();
text
 pg_is_in_recovery
-------------------
 t
(1 row)
sql
-- 核对数据是否符合预期
SELECT max(id) AS max_id, count(*) AS cnt FROM important_table;
SELECT * FROM important_table ORDER BY id DESC LIMIT 5;
sql
-- 确认无误后提升
SELECT pg_promote();
text
 pg_promote
------------
 t
(1 row)
sql
-- 提升后再确认一次
SELECT pg_is_in_recovery();
text
 pg_is_in_recovery
-------------------
 f
(1 row)

如果核对后发现恢复目标选得不对(例如停在误操作之后了),正确做法是停止服务、重新配置目标、重新从基础备份开始恢复,而不是试图在 pause 状态下"往回退"——恢复只能单调向前。

注意事项 ​

不要在 postgresql.conf 里长期保留恢复参数。 恢复参数是临时的。如果它们留在那里,下次意外以恢复模式启动时,实例会尝试再次恢复,可能造成混乱。更安全的做法是写入 postgresql.auto.conf(因为 ALTER SYSTEM 生成的配置集中在这里,便于用 ALTER SYSTEM RESET 清理),或者恢复结束后手工移除。

restore_command 找不到文件时立即返回非 0。 这是官方明确要求的语义。如果命令内部 sleep 或重试,会把恢复进度拖成"看起来卡住"。远端拉取一定要加超时。

recovery_target_xid 的停止语义与直觉不同。 它按事务 ID 分配顺序停止,而不是提交顺序。能用时间或 LSN 就别用 XID。

recovery_target_action 默认值是 pause。 忘记设置它会得到"恢复完了但只读"的结果。自动化脚本里务必显式指定 promote。

recovery.signal 与 standby.signal 不能共存。 从基础备份搭备库时如果用错了信号文件(用了 recovery.signal),实例会在重放到 WAL 末尾后停止甚至提升,而不是持续跟随主库。

恢复目标必须落在 [备份起点, 归档末尾] 区间内。 超出区间会导致恢复失败(目标太晚)或立即判定不可达(目标太早)。恢复前先用 restore_command 手工拉一个段验证归档可用性,再全量恢复。

恢复过程中不要并发访问数据目录。 任何外部进程(备份软件、同步工具、手工 cp)都不能在恢复期间读写数据目录。

archive_cleanup_command 会删除文件且不可逆。 在多实例共享归档目录的场景下启用它,风险极高。默认建议不启用,交由独立策略管理归档保留。

recovery_min_apply_delay 会放大切换时的数据损失。 设置了 30 分钟延迟,意味着主库故障切到该备库时,最多可能丢 30 分钟数据。因此延迟备库通常应与"正常同步备库"并存,而不是替代它。

恢复完成后实例处于新时间线,需要立即重建归档与备份链路。 恢复完就不管,会让新实例实际上"无保护"。

不要忘记恢复前的现场保全。 把原数据目录改名保留,是恢复失败时唯一的退路。删除是不可逆的。

最佳实践 ​

  1. 把恢复参数写入 postgresql.auto.conf 而不是手工编辑 postgresql.conf。 前者可以用 ALTER SYSTEM RESET ALL 或逐项 ALTER SYSTEM RESET 清理,且不会被配置管理工具覆盖。

  2. 恢复前先做一次"取 WAL"预检。 手工执行一次 restore_command 的等价命令,确认能取到目标区间的第一个和最后一个 WAL 段。这一步能提前发现归档缺段、权限、网络等问题,避免恢复跑到一半才失败。

  3. 显式设置 recovery_target_action。 自动化恢复脚本必须指定 promote;需要人工核对的场景则明确用 pause,并在 Runbook 里写清"核对什么、怎么判断、怎么继续"。

  4. 优先用命名还原点作为恢复目标。 recovery_target_name 的语义最稳定,不依赖时钟精度、不依赖事务 ID 分配顺序。把"打还原点"作为高风险操作的固定前置步骤。

  5. 配置里保留 recovery_target_inclusive 的显式取值。 边界是否包含会导致"差一条记录",在审计严格的场景下这是不可接受的模糊。显式写出来,避免依赖默认值。

  6. 恢复用独立实例或独立端口。 不要在生产实例的原数据目录上直接做恢复,除非已做好现场保全。把恢复放到另一台机器或另一个端口,可以在不影响生产的前提下核对数据,再从恢复实例导出所需数据。

  7. 把恢复参数模板化并纳入版本管理。 把参数组合写成模板文件(按目标类型分类),恢复时只需填空。避免在事故中临时手写参数。

  8. 在恢复脚本里加入自动校验。 恢复启动后自动等待并检查日志关键字(如 archive recovery complete),并执行几个关键业务查询做数据核对,把结果输出到报告。

  9. 为 restore_command 准备多条回退路径。 例如"先查本地缓存目录,再查对象存储",用 shell 的 || 串联。这样即使某一路径不可用,恢复也能继续。

  10. 定期验证"归档目录到恢复目标"的可达区间。 定期列出归档中最早与最新的 WAL 段,确认最远可恢复时间点符合 RPO 承诺。

  11. 延迟备库只作为补充手段。 它的价值在于缩短"发现得快"的误操作的恢复时间,不能替代 PITR。部署时同时保留一个无延迟的同步备库用于高可用切换。

  12. 恢复完成后立即执行三项收尾。 重做一次基础备份、确认归档链路恢复、验证监控告警恢复正常。缺少任何一项,实例都处于"看起来正常但实际无保护"的状态。

下一节

继续学习:按时间 / LSN / 事务 ID 恢复

参考链接 ​