按时间 / LSN / 事务 ID 恢复
知道了恢复配置怎么写,接下来最关键的实操问题就是:恢复到哪个点。PostgreSQL 提供了四种恢复目标类型——命名还原点、时间戳、LSN、事务 ID,它们在精度、可靠性、易用性上各有取舍,选错了会得到"看起来恢复了、实际差了半小时"的结果,或者干脆恢复失败。
这一页的核心是把这四种目标类型的语义、边界、误差来源讲清楚,并给出"误删表恢复"这类典型场景的完整实战。理解一个关键前提会让整页内容更容易吸收:恢复目标是一个"停止条件",不是一个"精确的手术刀"。PostgreSQL 在重放过程中一旦判定"已经越过了目标",就会停止;而"越过"的判断依据,对每种目标类型是不同的。
再强调一个后面会反复出现的边界:可达的恢复区间是 [基础备份的起点, 已归档 WAL 的末尾]。目标太早(早于基础备份的起始检查点)无法到达;目标太晚(晚于最后一段归档 WAL 覆盖的时间)也无法到达。选择目标之前,先确认它落在这个区间内。
前置知识
基础概念
四种目标类型速览
| 目标类型 | 参数 | 精度决定因素 | 最适合 | 主要风险 |
|---|---|---|---|---|
| 命名还原点 | recovery_target_name | 精确到 WAL 记录 | 事前打过还原点的关键操作 | 需要事前规划 |
| 时间戳 | recovery_target_time | 事务提交时间戳 | 已知误操作发生时间 | 时间戳来源不准 |
| LSN | recovery_target_lsn | 精确到字节位置 | 已从 WAL 定位到具体记录 | 需要能读 WAL |
| 事务 ID | recovery_target_xid | 事务分配顺序 | 已知具体事务 ID | 语义与直觉不符 |
| 一致性点 | recovery_target = 'immediate' | 第一个一致点 | 只要"能启动" | 恢复点最早、最不精确 |
目标之间的互斥关系
recovery_target_name、recovery_target_time、recovery_target_xid、recovery_target_lsn 这四项最多只能设置一个。设置多个会导致服务端报错并拒绝启动。
recovery_target(取值 immediate)是一个特殊的存在:它表示"不指定具体目标,到达第一个一致性点就停"。它与其他四项语义上互斥,实际上当 immediate 生效时其他目标参数不会被使用。
recovery_target_inclusive 的作用
recovery_target_inclusive 决定"恰好等于目标的那条记录是否被包含",默认 on(包含)。
| 目标类型 | inclusive = on(默认) | inclusive = off |
|---|---|---|
recovery_target_time | 包含命中时间的那条记录 | 不包含,停在其之前 |
recovery_target_xid | 包含该事务 | 停在该事务之前 |
recovery_target_lsn | 包含到达该 LSN 的记录 | 不包含该记录 |
recovery_target_name | 包含还原点记录本身 | 停在其之前 |
这个参数在"误操作恰好是某条记录"时很关键:如果你已经精确定位到"某条 DELETE 的 LSN",那么必须用 inclusive = off,否则恢复后那条 DELETE 依然生效。
时间戳的三种来源
recovery_target_time 的比较对象是 WAL 中记录的事务提交时间戳。这个时间戳由主库在提交时写入,因此它的准确性取决于:
- 主库系统时钟是否准确(是否启用 NTP);
- 时区是否理解正确(建议显式带时区偏移,如
+08); - 事务的"提交时间"与"业务感知的发生时间"是否一致。
常见误区是用"应用日志里的时间"作为目标,而应用日志的时间可能是请求开始时间,而非数据库提交时间。更稳妥的做法是留一点余量(例如目标时间比应用日志时间早 1 秒),或者优先使用命名还原点、LSN 这类不依赖时钟的方式。
LSN 的格式与表示
LSN 形如 0/16C4D00:斜杠左侧是高 32 位十六进制,右侧是低 32 位十六进制。它是一个 64 位字节偏移量。LSN 可以在 SQL 中作为字符串书写并隐式转换为 pg_lsn 类型:
-- 这两种写法都合法
SELECT '0/16C4D00'::pg_lsn;
SELECT pg_walfile_name('0/16C4D00'::pg_lsn);LSN 也可以参与算术(通过 pg_lsn 的加减运算符),例如在"目标 LSN 上减一点余量"时很有用。
事务 ID 的语义陷阱
recovery_target_xid 按事务 ID 的分配顺序而非提交顺序停止。事务 ID 在事务"第一次写入"时分配,而提交顺序与分配顺序可能完全不同:
事务 A:分配 XID 100 → 很晚才提交
事务 B:分配 XID 101 → 立刻提交
按分配顺序:100 < 101
按提交顺序:B 先,A 后因此 recovery_target_xid = '100' 的语义是"重放到所有 XID ≤ 100 的更改都已应用",而不是"恢复到事务 A 之前"。如果只想精确停到某个事务之前,用 LSN 或用事务提交时间更可靠。
语法与用法
四种目标的配置写法
# ---- 方式一:命名还原点 ----
recovery_target_name = 'before_batch_fix_20260928'
recovery_target_inclusive = on
recovery_target_action = 'promote'# ---- 方式二:时间戳 ----
recovery_target_time = '2026-09-20 10:30:00+08'
recovery_target_inclusive = on
recovery_target_action = 'promote'# ---- 方式三:LSN ----
recovery_target_lsn = '0/16C4D00'
recovery_target_inclusive = off
recovery_target_action = 'promote'# ---- 方式四:事务 ID ----
recovery_target_xid = '743'
recovery_target_inclusive = off
recovery_target_action = 'promote'# ---- 方式五:只要一致性点 ----
recovery_target = 'immediate'
recovery_target_action = 'promote'创建命名还原点
-- 在关键操作前打下还原点
SELECT pg_create_restore_point('before_price_adjust_20260928'); pg_create_restore_point
--------------------------
0/1B2C340
(1 row)注意官方的提醒:避免创建同名的多个还原点,因为恢复时会停在第一个匹配的还原点。因此还原点名称应包含时间戳或序号,保证唯一。
-- 推荐:名称带日期时间,便于追溯且天然唯一
SELECT pg_create_restore_point('before_price_adjust_' || to_char(now(), 'YYYYMMDD_HH24MISS'));查询当前 LSN 与 WAL 段
SELECT pg_current_wal_lsn() AS cur_lsn,
pg_walfile_name(pg_current_wal_lsn()) AS cur_seg,
pg_current_wal_insert_lsn() AS insert_lsn,
pg_current_wal_flush_lsn() AS flush_lsn; cur_lsn | cur_seg | insert_lsn | flush_lsn
------------+------------------------+------------+------------
0/1B2C340 | 0000000100000000000000B5 | 0/1B2C340 | 0/1B2C340
(1 row)三个 LSN 的区别:
| 函数 | 含义 | 用途 |
|---|---|---|
pg_current_wal_insert_lsn() | 逻辑上已插入的位置 | 调试 |
pg_current_wal_lsn() | 已写出到操作系统的位置 | 归档关注的"外部可见末尾" |
pg_current_wal_flush_lsn() | 已刷到持久存储的位置 | 判断持久化进度 |
详细说明
各目标类型的比较
把四种方式的工程特性并列起来看,选择会清晰很多。
| 维度 | 命名还原点 | 时间戳 | LSN | 事务 ID |
|---|---|---|---|---|
| 是否需要事前准备 | 需要(打还原点) | 不需要 | 不需要 | 不需要 |
| 是否需要读 WAL | 不需要 | 不需要 | 建议(定位) | 不需要 |
| 精度 | 极高(WAL 记录级) | 中(受时钟影响) | 最高(字节级) | 低(顺序语义特殊) |
| 受时钟影响 | 否 | 是 | 否 | 否 |
| 目标唯一性 | 需保证名称唯一 | 时间可能不唯一 | 唯一 | XID 唯一 |
| 使用难度 | 低 | 低 | 中 | 中 |
| 典型场景 | 高风险变更前 | 已知误操作时间 | 已定位到具体记录 | 已知事务号 |
工程上的推荐顺序是:命名还原点 > LSN > 时间戳 > 事务 ID。命名还原点同时具备"精确"和"易用"两个优点,唯一成本是事前需要打一个点;而事务 ID 由于语义不太直观,除非确有必要,否则不建议作为首选。
命名还原点的内部机制
pg_create_restore_point(name) 做两件事:
- 在 WAL 中写入一条特殊的"还原点"记录,并返回该记录的位置(
pg_lsn); - 由于这条记录必须在 WAL 中落定,函数会等待并确保位置稳定。
还原点记录在恢复时是可识别的,因此 recovery_target_name 能精确命中它。这也是为什么还原点是最可靠的目标类型——它不依赖任何外部信息的解释。
一个使用细节:还原点记录本身也占用 WAL 空间,且会被归档。因此还原点是"永久可查"的(只要归档还在),不像应用日志那样会滚动清理。
时间戳目标的误差来源
用 recovery_target_time 时,下列因素会引入误差:
| 误差来源 | 表现 | 缓解方式 |
|---|---|---|
| 主库时钟不准 | 目标时间与实际提交时间错位 | 开启 NTP,定期校时 |
| 时区理解错误 | 目标整体偏移若干小时 | 显式书写时区偏移 |
| 应用日志时间是请求开始时间 | 目标偏晚 | 目标提前留余量 |
| 长事务跨越目标时间 | 提交时间晚于目标但影响更早 | 结合 LSN 校验 |
| 目标时间落在两条记录之间 | 停在最近的一条边界 | 用 inclusive 明确边界 |
时区问题尤其常见:'2026-09-20 10:30:00' 不写时区时,会按数据库的 TimeZone 设置解释;如果数据库时区是 UTC,而人的意图是东八区的 10:30,就会整体偏移 8 小时。因此永远显式写时区偏移。
如何从 WAL 定位目标 LSN
这是"精确恢复"的核心技能。pg_waldump 可以读出 WAL 的记录内容,包括每条记录的类型、事务号、LSN 与描述:
pg_waldump -p /mnt/wal_archive 0000000100000000000000B3rmgr: Standby len (rec/tot): 50/ 50, tx: 0, lsn: 0/16B3748, prev 0/16B3710, desc: RUNNING_XACTS nextXid 745 latestCompletedXid 744 oldestRunningXid 745
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
rmgr: Transaction len (rec/tot): 46/ 46, tx: 743, lsn: 0/16C4D88, prev 0/16C4D00, desc: COMMIT 2026-09-20 10:31:12.339251+08从上面可以看出:
- 误删的记录是
tx: 743的DELETE,位置0/16C4D00; - 该事务的提交记录在
lsn: 0/16C4D88,提交时间10:31:12。
如果要把这条 DELETE 排除在外,可以选择:
| 方案 | 设置 | 效果 |
|---|---|---|
| 按 LSN 停在删除前 | recovery_target_lsn = '0/16C4D00' + inclusive = off | 精确排除该条 |
| 按时间停在提交前 | recovery_target_time = '2026-09-20 10:31:12.3' + inclusive = off | 受时钟影响 |
| 用事务 ID | recovery_target_xid = '743' + inclusive = off | 语义为"停在 XID<743" |
pg_waldump 的常用参数:
| 参数 | 作用 |
|---|---|
-p / --path | 指定 WAL 目录 |
-n / --limit | 限制读取的记录条数 |
-s / --start | 指定起始 LSN |
-e / --end | 指定结束 LSN |
-t / --timeline | 指定时间线 |
-x / --xid | 只显示指定事务的记录 |
目标早于或晚于可达区间的处理
这是实操中最常见的两种"恢复失败"。
情况一:目标晚于最后一段归档 WAL。
表现为恢复一路重放到 WAL 末尾,然后日志提示未到达目标。原因可能是:
- 归档滞后(最后一段还没归档);
- 目标时间算错了(未来时间);
- 归档断档,导致 WAL 无法继续。
处理:先把归档补齐(触发 pg_switch_wal(),等待归档),或者修正目标时间。
情况二:目标早于基础备份的起点。
表现为启动时报错说目标早于最后一个检查点。原因很简单:基础备份本身就是从某个时刻开始的,你无法用它恢复到它之前的状态。
处理:只能使用更早的基础备份。因此基础备份的保留周期决定了"最远能恢复到多久以前"。
可达区间示意:
时间 ──────────────────────────────────────────────────►
[备份 B1 起点] ──────── [误操作] ──────── [备份 B2 起点] ──── [归档末尾]
│ │ │
└── 用 B1 可恢复的区间 ────────────────────┘ │
└── 用 B2 可恢复 ─┘recovery_target = 'immediate' 的特例
immediate 的含义是"只要数据库到达第一个一致性状态就停止重放"。它不关心任何具体时刻,只要求能启动。
它的用途包括:
- 只想验证一份基础备份能否启动(不追求恢复点);
- 从基础备份快速创建一份只读拷贝;
- 恢复到"备份结束时"的状态,作为增量备份的基线。
要理解它的生效条件:只有当恢复过程中遇到第一个一致性点时它才起作用。而一致性点的到达本身需要重放足够的 WAL,因此"immediate"并不意味着"零重放"。
recovery_target = 'immediate'
recovery_target_action = 'pause'时间戳精度与边界行为
recovery_target_time 的比较精度是微秒级(与 PostgreSQL 的 timestamptz 精度一致)。因此:
- 写
'2026-09-20 10:30:00+08'会被解释为10:30:00.000000; - 如果事务提交在
10:30:00.000500,默认inclusive = on会包含它; - 若希望"严格停在 10:30:00 之前",应写
10:29:59.999999或使用inclusive = off。
在实践中,更简单的做法是目标时间比"希望保留的最后一条数据"晚一点点,但早于误操作提交时间。给定几个毫秒的缓冲,比在边界上纠结更符合工程实际。
用 pg_waldump 制作恢复决策表
一个非常实用的实操方法:在 WAL 中把误操作前后的关键记录列出来,做成"恢复决策表",再据此选目标。
# 找出目标时间段内的所有事务提交记录
pg_waldump -p /mnt/wal_archive 0000000100000000000000B3 | grep 'COMMIT'rmgr: Transaction len (rec/tot): 46/ 46, tx: 741, lsn: 0/16B8A10, prev 0/16B89C8, desc: COMMIT 2026-09-20 10:28:41.112033+08
rmgr: Transaction len (rec/tot): 46/ 46, tx: 742, lsn: 0/16BB220, prev 0/16BB1D8, desc: COMMIT 2026-09-20 10:29:55.870412+08
rmgr: Transaction len (rec/tot): 46/ 46, tx: 743, lsn: 0/16C4D88, prev 0/16C4D00, desc: COMMIT 2026-09-20 10:31:12.339251+08决策表:
| 事务 | 提交时间 | LSN | 说明 |
|---|---|---|---|
| 741 | 10:28:41.112 | 0/16B8A10 | 正常业务 |
| 742 | 10:29:55.870 | 0/16BB220 | 正常业务(最后一条想保留的) |
| 743 | 10:31:12.339 | 0/16C4D88 | 误操作事务(要排除) |
据此可以选:
recovery_target_time = '2026-09-20 10:30:00+08'(介于 742 与 743 之间,安全);- 或
recovery_target_lsn = '0/16C4D00'+inclusive = off(精确到记录); - 或
recovery_target_xid = '743'+inclusive = off。
从恢复实例中挽回单表数据
PITR 恢复是整个集簇级的,但实际故障常常只是"一张表被误删"。此时最实用的模式是"恢复出一个临时实例,从里面取数据":
生产实例(受损) 临时恢复实例(历史状态)
│ │
│ 1. 用基础备份+归档恢复出一个临时实例
│ │
│ 2. 从临时实例 pg_dump 目标表
│ │
│ 3. 把 dump 导入生产实例
▼ ▼
继续服务 验证后销毁这种模式的优点是:
- 生产实例的当前状态不受影响(不需要回退整个实例);
- 恢复可以放到另一台机器,不影响生产资源;
- 通过
pg_dump只搬运需要的表,粒度可控。
代价是需要额外的机器与时间,且必须是"误删除之外还有其他数据写入"的场景——如果整库都不可用,还是得整实例恢复。
实战示例
示例一:按时间恢复(最常用流程)
# 1. 确定目标时间:误操作提交时间 10:31:12,取 10:30:00 作为目标
# 2. 准备临时恢复目录(不影响生产)
mkdir -p /tmp/pitr_restore
chown postgres:postgres /tmp/pitr_restore
chmod 0700 /tmp/pitr_restore
# 3. 展开基础备份
tar -xzf /backup/base_20260920.tar.gz -C /tmp/pitr_restore
# 4. 写恢复参数
cat > /tmp/pitr_restore/postgresql.auto.conf <<'EOF'
restore_command = 'cp /mnt/wal_archive/%f %p'
recovery_target_time = '2026-09-20 10:30:00+08'
recovery_target_inclusive = on
recovery_target_action = 'pause'
EOF
# 5. 创建恢复信号文件
touch /tmp/pitr_restore/recovery.signal# 6. 以独立端口启动(不影响生产实例)
/usr/lib/postgresql/18/bin/pg_ctl \
-D /tmp/pitr_restore \
-o "-p 5433 -c listen_addresses='127.0.0.1'" \
-l /tmp/pitr_restore/restore.log \
start# 7. 观察恢复日志
tail -f /tmp/pitr_restore/restore.logLOG: starting point-in-time recovery to 2026-09-20 10:30:00+08
LOG: restored log file "0000000100000000000000B3" 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: database system is ready to accept read-only connections示例二:按 LSN 恢复(精确排除某条记录)
# 已知误删除记录 LSN 为 0/16C4D00,停在该记录之前
restore_command = 'cp /mnt/wal_archive/%f %p'
recovery_target_lsn = '0/16C4D00'
recovery_target_inclusive = off
recovery_target_action = 'promote'-- 恢复后验证:目标数据应存在
SELECT * FROM products WHERE id = 12345; id | name | price
-------+-----------+-------
12345 | 样品A | 19.90
(1 row)示例三:用命名还原点恢复
-- 事前:在执行批量价格调整前创建还原点
BEGIN;
SELECT pg_create_restore_point('before_bulk_price_20260928');
-- 记录返回的 LSN,写入操作日志
COMMIT; pg_create_restore_point
--------------------------
0/1B2C340
(1 row)# 事后:恢复时直接引用该名称
restore_command = 'cp /mnt/wal_archive/%f %p'
recovery_target_name = 'before_bulk_price_20260928'
recovery_target_action = 'promote'示例四:误删表恢复完整实战
场景:orders 表在 10:31 被误执行 TRUNCATE,需要把数据找回,同时不影响其他表的最新数据。
# 第 1 步:确认误操作时间(从审计日志或监控中查到)
# 误操作时间:2026-09-20 10:31:12
# 选择恢复目标:2026-09-20 10:31:00+08# 第 2 步:在临时目录恢复出一个历史实例
mkdir -p /tmp/pitr_orders
tar -xzf /backup/base_20260920.tar.gz -C /tmp/pitr_orders
cat > /tmp/pitr_orders/postgresql.auto.conf <<'EOF'
restore_command = 'cp /mnt/wal_archive/%f %p'
recovery_target_time = '2026-09-20 10:31:00+08'
recovery_target_action = 'pause'
EOF
touch /tmp/pitr_orders/recovery.signal
chown -R postgres:postgres /tmp/pitr_orders
chmod 0700 /tmp/pitr_orders# 第 3 步:启动临时实例(端口 5433)
pg_ctl -D /tmp/pitr_orders -o "-p 5433" -l /tmp/pitr_orders/restore.log start-- 第 4 步:在临时实例上确认数据还在
SELECT count(*) FROM orders; count
--------
842311
(1 row)# 第 5 步:只导出需要的表(数据 + 结构分开处理更灵活)
pg_dump -h 127.0.0.1 -p 5433 -U postgres -d appdb \
-t public.orders --data-only --column-inserts \
-f /tmp/orders_data.sql# 第 6 步:在生产实例上恢复数据
# 由于生产实例的 orders 表已被清空,可以直接导入数据
psql -h 127.0.0.1 -p 5432 -U postgres -d appdb -f /tmp/orders_data.sql-- 第 7 步:验证生产实例数据
SELECT count(*) FROM orders; count
--------
842311
(1 row)# 第 8 步:确认无误后销毁临时实例
pg_ctl -D /tmp/pitr_orders stop
rm -rf /tmp/pitr_orders /tmp/orders_data.sql这个流程的关键点是:用临时实例做"时间旅行",只用 pg_dump/psql 搬运需要的表,从而既找回了数据,又不影响生产实例上误操作之后的其他正常写入。
示例五:immediate 恢复用于验证备份可用性
restore_command = 'cp /mnt/wal_archive/%f %p'
recovery_target = 'immediate'
recovery_target_action = 'promote'这个配置的用途是"最快地验证一份基础备份能启动"。恢复会在到达第一个一致性点后停止并提升,因此速度最快。验证完即可销毁,用于定期巡检备份可用性。
示例六:查询恢复进度(恢复中执行)
如果实例在恢复过程中已经可以提供只读连接(达到一致性点后),可以查询进度:
SELECT pg_is_in_recovery() AS in_recovery,
pg_last_wal_replay_lsn() AS replayed,
pg_last_xact_replay_timestamp() AS last_replay_time,
now() - pg_last_xact_replay_timestamp() AS replay_lag; in_recovery | replayed | last_replay_time | replay_lag
-------------+------------+---------------------------+------------
t | 0/16C4D00 | 2026-09-20 10:30:58.701+08 | 00:00:12.4
(1 row)last_replay_time 可以帮助判断"已经重放到哪个时刻了",是恢复过程中最实用的观测手段。
注意事项
设置多个目标参数会导致启动失败。 recovery_target_name / _time / _xid / _lsn 只能四选一。切换目标时务必把上一个移除,而不是注释掉(注释在 postgresql.auto.conf 中不可用)。
时间戳一定要带时区。 不带时区的时间会按数据库的 TimeZone 参数解释,容易造成数小时的整体偏移。写成 '2026-09-20 10:30:00+08' 这样的形式。
recovery_target_xid 的停止语义容易误解。 它按事务 ID 分配顺序停止,不是提交顺序。除非有明确理由,优先使用时间或 LSN。
还原点名称要唯一。 同名还原点会导致恢复停在第一个匹配处。名称中带上时间戳或序号,天然避免冲突。
目标必须落在可达区间内。 目标早于基础备份起点 → 不可达,只能用更早的备份;目标晚于归档末尾 → 恢复会失败或停不到目标。
inclusive 的取值要与"排除意图"一致。 想排除某条记录时必须用 inclusive = off,否则边界那一条会被包含进来。
恢复只能单调向前,不能后退。 一旦发现目标选错,只能重新从基础备份开始恢复,不能在 pause 状态下"往回退"。
恢复实例要隔离端口与数据目录。 在同一台机器上做临时恢复时,务必使用不同的端口与不同的数据目录,避免误连、误写、误删。
从恢复实例导出数据时注意类型与约束。 --data-only 只导出数据,如果生产表结构已变化,可能导入失败。必要时先用 --schema-only 校对结构差异。
恢复期间不要在生产实例上做"清理"动作。 例如发现误删后立刻重建表、立刻重启服务等,这些都会改变现状,让"回到过去"变得更复杂。先保全现场。
最佳实践
优先使用命名还原点作为恢复目标。 它在精度与易用性上综合最优。把"高风险操作前打还原点"固化为标准流程,甚至写进发布脚本。
还原点命名带时间戳,并记录到变更/审计系统。 名称形如
before_<动作>_<YYYYMMDD_HH24MISS>,既保证唯一,又便于事后检索。同时把返回的 LSN 一并记录。时间戳目标显式带时区偏移。 这是一个几乎零成本的改动,却能避免最常见的"整体偏移若干小时"事故。
用
pg_waldump建立恢复决策表。 在恢复前把关键事务的提交时间与 LSN 列出来,明确"哪条要保留、哪条要排除",避免在时间戳上做模糊判断。恢复前先确认可达区间。 列出归档中最早与最新的 WAL 段,确认目标落在区间内。这一步可以在几分钟内完成,避免几小时的恢复跑到最后才失败。
临时恢复实例与生产实例严格隔离。 使用独立目录、独立端口、独立内存参数,必要时限制
listen_addresses为本地回环,避免被业务误连。用"临时实例 + 单表导出"处理单表故障。 除非整库不可用,否则不要为了找回一张表而回退整个生产实例。
在自动化脚本里显式设置
recovery_target_action。 默认是pause,自动化场景通常需要promote;需要在恢复后核对数据的场景则显式pause,并在脚本里等待人工确认。记录每次恢复的目标参数与结果。 包括目标类型、目标值、恢复耗时、实际停下的 LSN 与时间。这些记录对优化 RTO 与后续演练极有价值。
不要依赖"应用日志时间"作为唯一依据。 应用日志时间与数据库提交时间可能有偏差。能用还原点或 LSN 就别用时间。
定期演练"从归档中定位目标 LSN"这个技能。 这是灾难恢复中最能节省时间的技能之一。把流程写成 Runbook,包含
pg_waldump的常用命令与判读方法。恢复完成后立即处理时间线变化。 恢复并提升后时间线递增,需要更新监控基线、重新做基础备份、确认归档链路恢复。否则新实例处于"无保护"状态。
下一节
参考链接
- PostgreSQL 官方文档:Recovery Target Settings
- PostgreSQL 官方文档:Continuous Archiving and Point-in-Time Recovery (PITR)
- PostgreSQL 官方文档:Recovery Configuration
- PostgreSQL 官方文档:System Administration Functions — Backup Control Functions
- PostgreSQL 官方文档:pg_waldump
- PostgreSQL 官方文档:pg_dump
- PostgreSQL 官方文档:pg_restore
- PostgreSQL 官方文档:Log-Shipping Standby Servers
- PostgreSQL 官方文档:pg_ctl