PIGSTY

时间点恢复

从备份恢复 PostgreSQL

您可以使用预配置的 pgbackrest 在 Pigsty 中执行时间点恢复(PITR)。

  • 手动方式:使用 pg-pitr 提示脚本进行 PITR,手动操作,更灵活但更复杂。
  • 剧本方式:使用 pgsql-pitr.yml 剧本进行 PITR,自动化,但灵活性较低且更容易出错。

如果您对配置非常熟悉,可以使用全自动剧本, 否则,考虑逐步手动操作


快速开始

如果您想将 pg-meta 集群回滚到之前的时间点,添加 pg_pitr

pg-meta:
  hosts: { 10.10.10.10: { pg_seq: 1, pg_role: primary } }
  vars:
    pg_cluster: pg-meta2
    pg_pitr: { time: '2025-07-13 10:00:00+00' }  # 从最新备份恢复

然后运行 pgsql-pitr.yml 剧本,它将把 pg-meta 集群回滚到指定的时间点。

./pgsql-pitr.yml -l pg-meta

恢复 PITR

恢复的集群上的 archive_mode 将被禁用,以防止不必要的 WAL 写入。 如果恢复的数据库状态正常,您可以启用 archive_mode 并进行全量备份。

postgres @ pg-meta $
psql -c 'ALTER SYSTEM RESET archive_mode; SELECT pg_reload_conf();'
pg-backup full    # 进行新的全量备份

恢复目标

您可以在 pg_pitr 中指定不同类型的恢复目标,但它们是互斥的:

  • time:恢复到哪个时间点?
  • name:恢复到命名的恢复点(由 pg_create_restore_point 创建)
  • xid:恢复到特定的事务 ID(TXID/XID)
  • lsn:恢复到特定的 LSN(日志序列号)点

如果指定了上述任何参数,恢复 type 将相应设置, 否则将设置为 latest(WAL 归档流的末尾)。 特殊的 immediate 类型可用于指示 pgbackrest 通过在第一个一致点停止来最小化恢复时间。

目标类型

pg_pitr: { }  # 恢复到最新状态(wal 归档流结束)
pg_pitr: { time: "2025-07-13 10:00:00+00" }
pg_pitr: { lsn: "0/4001C80" }
pg_pitr: { xid: "250000" }
pg_pitr: { name: "some_restore_point" }
pg_pitr: { type: "immediate" }

按时间

最常用的目标是时间点;您可以指定要恢复到的时间点:

恢复到时间点
./pgsql-pitr.yml -e '{"pg_pitr": { "time": "2025-07-13 10:00:00+00" }}'

时间应该是有效的 PostgreSQL TIMESTAMP,建议使用 YYYY-MM-DD HH:MM:SS+TZ

按名称

您可以使用 pg_create_restore_point 创建命名的恢复点:

SELECT pg_create_restore_point('shit_incoming');

并在 PITR 中使用该命名恢复点:

./pgsql-pitr.yml -e '{"pg_pitr": { "name": "shit_incoming" }}'

按 XID

如果您有一个意外删除某些数据的事务,最好的恢复方法是将数据库恢复到该事务之前的状态。

恢复到事务之前
./pgsql-pitr.yml -e '{"pg_pitr": { "xid": "250000", exclusive: true }}'

您可以从监控仪表板找到确切的事务 ID,或从 CSVLOG 的 TXID 中找到它。

包含 vs 排除

目标参数默认是"包含"的,这意味着恢复将包含目标点。 exclusive 标志将排除那个确切的目标,比如 xid 24999 将是最后一个被重放的事务

这仅适用于 timexidlsn 恢复目标,详情请查看 recovery_target_inclusive

按 LSN

PostgreSQL 使用 LSN(日志序列号)来标识 WAL 记录的位置。 您可以在任何地方找到它,比如 Pigsty 仪表板的 PG LSN 面板。

恢复到 LSN
./pgsql-pitr.yml -e '{"pg_pitr": { "lsn": "0/4001C80", timeline: "1" }}'

要恢复到 WAL 流中的确切点,您还可以指定 timeline 参数(默认为 latest


恢复源

  • cluster:恢复哪个集群?默认使用当前的 pg_cluster,您可以在同一个 pgbackrest 仓库中使用任何其他集群
  • repo:覆盖备份仓库,使用与 pgbackrest_repo 相同的格式
  • set:默认使用 latest 备份集,但您可以指定特定的 pgbackrest 备份标签

Pigsty 将从 pgbackrest 备份仓库恢复,如果您使用集中式备份仓库(如 MinIO/S3), 您可以指定另一个"stanza"(另一个集群的备份目录)来恢复。

pg-meta2:
  hosts: { 10.10.10.11: { pg_seq: 1, pg_role: primary } }
  vars:
    pg_cluster: pg-meta2
    pg_pitr: { cluster: pg-meta }  # 从 pg-meta 集群备份恢复

上述配置将标记 PITR 过程使用 pg-meta stanza。 您也可以通过 CLI 参数传递 pg_pitr 参数:

使用 pg-meta 备份恢复 pg-meta2
./pgsql-pitr.yml -l pg-meta2 -e '{"pg_pitr": { "cluster": "pg-meta" }}'

从另一个集群进行 pitr 时,您也可以使用这些目标:

./pgsql-pitr.yml -l pg-meta2 -e '{"pg_pitr": { "cluster": "pg-meta", "time": "2025-07-14 08:00:00+00" }}'

分步执行

这种方法是半自动的,您将参与 PITR 过程以做出关键决策。

例如,此配置将把 pg-meta 集群本身恢复到指定的时间点

pg-meta:
  hosts: { 10.10.10.10: { pg_seq: 1, pg_role: primary } }
  vars:
    pg_cluster: pg-meta2
    pg_pitr: { time: '2025-07-13 10:00:00+00' }  # 从最新备份恢复

让我们逐步执行:

./pgsql-pitr.yml -l pg-meta -t down     # 暂停 patroni HA
./pgsql-pitr.yml -l pg-meta -t pitr     # 运行 pitr 过程
./pgsql-pitr.yml -l pg-meta -t up       # 生成 pgbackrest 配置和恢复脚本
# down                 : # 停止 ha 并关闭 patroni 和 postgres
#   - pause            : # 暂停 patroni 自动故障转移
#   - stop             : # 停止 patroni 和 postgres 服务
#     - stop_patroni   : # 停止 patroni 服务
#     - stop_postgres  : # 停止 postgres 服务
# pitr                 : # 执行 PITR 过程
#   - config           : # 生成 pgbackrest 配置和恢复脚本
#   - restore          : # 运行 pgbackrest 恢复命令
#   - recovery         : # 启动 postgres 并完成恢复
#   - verify           : # 验证恢复的集群控制数据
# up:                  : # 启动 postgres / patroni 并恢复 ha
#   - etcd             : # 在启动前清理 etcd 元数据
#   - start            : # 启动 patroni 和 postgres 服务
#     - start_postgres : # 启动 postgres 服务
#     - start_patroni  : # 启动 patroni 服务
#   - resume           : # 恢复 patroni 自动故障转移

PITR 定义

pg_pitr 参数中有更多可用选项,以下是一些可用的参考项:

pg_pitr:                        # 定义 PITR 任务
    cluster: "some_pg_cls_name"   # 源集群名称
    type: latest                  # 恢复目标类型:time、xid、name、lsn、immediate、latest
    time: "2025-01-01 10:00:00+00" # 恢复目标:时间,与 xid、name、lsn 互斥
    name: "some_restore_point"    # 恢复目标:命名恢复点,与 time、xid、lsn 互斥
    xid:  "100000"                # 恢复目标:事务 ID,与 time、name、lsn 互斥
    lsn:  "0/3000000"             # 恢复目标:日志序列号,与 time、name、xid 互斥
    timeline: latest              # 目标时间线,可以是整数,默认为 latest
    exclusive: false              # 排除目标点,默认为 false?
    action: pause                 # 恢复后操作:pause、promote、shutdown
    archive: false                # 保留归档设置?默认为 false
    db_exclude: [ template0, template1 ]
    db_include: []
    link_map:
      pg_wal: '/data/wal'
      pg_xact: '/data/pg_xact'
    process: 4                    # 并行恢复进程
    repo: {}                      # 要恢复的仓库
    data: /pg/data                # 恢复数据的位置
    port: 5432                    # 恢复实例的监听端口