Postgres的wal和PITR时间点恢复

目录

研究了Postgres的库数据恢复和转移,再来研究一下PITR按时间点恢复

类比到MySQL,因为我们是运维,不是专业的DBA,所以恢复到正确数据即可

那跟阿里云以及自建的MySQL恢复一样,首先都要有一个每天的基础备份,然后类比MySQL的Binlog,Postgres这里就相当于wal。

这么类比就对了,那么恢复过程的思路是一样的:

  • 首先建立一个新的实例
  • 第二步把每天的基础物理全备给恢复上去
  • 第三步把之后的wal日志传到新实例,恢复到指定时间点
  • 第四步最后把表或库Dump下来,灌入到旧实例的新表或新库

那我们一步一步来解释:

一、每天建立一个基础备份,这样在Base基础上,只需恢复当天的wal,速度够快

建立每天的Base基础物理备份

 1pg_basebackup -Ft -Pv -Xf -z -Z5 -U postgres -h localhost -p 5432 -D /pg_backup
 2
 3解释一下:
 4    -Ft:
 5        指定备份格式为 tar。
 6        如果使用 tar 格式,备份会输出 tar 文件,并且不需要直接访问 PostgreSQL 数据目录。
 7    -Pv:
 8        -P:显示备份进度。
 9        -v:启用详情模式(verbose),显示更多日志。
10    -Xf:
11        -X:控制 WAL 日志的处理方式,f 表示在备份中包含 WAL 文件(Write Ahead Logs),确保备份可以用于恢复到完整的一致状态。
12    -z:
13        启用压缩功能。
14    -Z5:
15        设置压缩级别为 5(压缩级别从 0 到 9,9 为最高压缩)。
16    -U postgres:
17        使用 postgres 用户来连接数据库。
18    -h localhost:
19        指定数据库主机为当前机器(localhost)。
20    -p 5432:
21        指定 PostgreSQL 监听端口为 5432(默认端口)。
22    -D /pg_backup:
23        将备份文件保存到指定路径 /pg_backup 中。

这样我们就在 /pg_backup 中有了备份文件,包括一个backup_manifest的文件清单,以及一个压缩包

1root@debian:/pg_backup# ls -lha
2total 1.8G
3drwxr-xr-x  3 root root 4.0K Jul 28 16:31 .
4drwxr-xr-x 20 root root 4.0K Jul 28 16:18 ..
5-rw-------  1 root root 760K Jul 28 16:21 backup_manifest
6-rw-------  1 root root 1.8G Jul 28 16:21 base.tar.gz

那这个base.tar.gz里面又都有什么呢?

 1/
 2├── base/                   # 每个数据库的文件
 3├── global/                 # 全局对象(角色、权限)
 4├── pg_wal/                 # WAL 日志
 5├── pg_xact/                # 事务状态
 6├── pg_clog/                # 事务提交信息
 7├── postgresql.auto.conf    # 自动配置文件
 8├── postgresql.conf         # 主配置文件
 9├── pg_hba.conf             # 访问控制文件
10├── pg_ident.conf           # 用户映射文件
11└── ...                     # 其他系统文件

我们先 ps axjf 看一把

image-20250728172232116

可以看到,-D的数据目录是在/var/lib/postgresql/13/main下,那base.tar.gz里面的内容跟/var/lib/postgresql/13/main下是一样的。

二、旧实例需要建立wal的归档模式
 1# ps axjf的结果中,看到配置文件是 /etc/postgresql/13/main/postgresql.conf
 2# 那就修改这个配置文件
 3
 4# 修改以下2行
 5# 启用归档
 6archive_mode = on
 7# WAL 日志归档路径
 8archive_command = 'cp %p /path_to_archive_directory/%f'
 9
10# 然后重启服务生效
11systemctl restart postgresql

以上做完后我们如果我们做了Base备份,然后wal的日志还在继续跑,那我们就需要手动触发一下wal写盘

1select pg_switch_wal();
2
3 pg_switch_wal
4---------------
5 0/13DAC308

会得到一个序列号:0/13DAC308

然后新的wal归档日志就放在:/path_to_archive_directory/目录下了,那原始的wal数据文件还在 /var/lib/postgresql/13/main/pg_wal 下

三、新实例恢复Base库和时间点:
 1# 找到新实例的数据目录,一把删空,然后把base.tar.gz解压进去
 2# 建恢复目录并清理旧数据
 3# 将解压后的备份移到数据库实例的实际数据目录(通常位于 /var/lib/postgresql/data)。清理旧目录后执行:
 4mv /pg_restore/ /var/lib/postgresql/data
 5
 6# 设置恢复配置文件
 7# 在数据目录中创建一个名为 recovery.signal 的空文件,同时在数据目录中新增恢复目标的配置文件 postgresql.auto.conf。
 8touch recovery.signal
 9
10#编辑或创建文件 postgresql.auto.conf:
11vi /var/lib/postgresql/data/postgresql.auto.conf
12
13# 添加以下内容:
14# 旧实例的wal文件需要事先copy到新实例的 /path_to_archive_directory 目录下
15primary_conninfo = ''
16restore_command = 'cp /path_to_archive_directory/%f %p'
17recovery_target_time = 'YYYY-MM-DD HH:MI:SS'
18recovery_target_action = 'pause'

说明:

restore_command:用于指定如何恢复 WAL 日志。这里的命令是从归档目录 /path_to_archive_directory/ 中拷贝 WAL 日志到 PostgreSQL 数据目录。

recovery_target_time:你希望恢复到的时间点精确到秒(UTC 时间)。

recovery_target_action:在完成恢复到目标时间后,pause 表示暂停恢复并进入只读模式

然后开始恢复:

 1# 确保 PostgreSQL 数据目录已准备好,删除目录下旧的 postmaster.pid 等文件:
 2rm /var/lib/postgresql/data/postmaster.pid
 3
 4# 启动 PostgreSQL 服务:
 5systemctl start postgresql
 6
 7# 确认恢复进度
 8# 观察 PostgreSQL 的日志文件(通常位于 /var/log/postgresql/postgresql-X.log,具体路径根据配置文件可能不同):
 9tail -f /var/log/postgresql/postgresql-X.log
10
11# 如果一切正常,你应该能看到以下内容:
12consistent recovery point reached at 0/16B6F98
13recovery stopping at specified recovery target
14
15# 退出恢复模式
16mv /var/lib/postgresql/data/standby.signal /var/lib/postgresql/data/standby.signal.bak
17
18# 退出恢复模式后,确认是只读模式
19SELECT pg_is_in_recovery();
20
21# 如果要进入可读可写的模式
22select pg_wal_replay_resume();
四、dump出新实例指定表或库的数据,然后灌回旧实例的新表或新库

这个过程就不多说了。

多说一句,可以恢复到某个时间点,事务或者wal序列号

1# 恢复到不同时间点
2# 假设第一次恢复后,你希望尝试恢复到另一个时间点,修改 postgresql.auto.conf 文件中的 recovery_target_time 然后同样重复以上步骤即可重新恢复。
3recovery_target_time = 'YYYY-MM-DD HH:MI:SS'
4
5# 以某个事务为目标:
6recovery_target_xid = '12345'
7
8#以某个 WAL 日志序列号为目标:
9recovery_target_lsn = '0/16B6F98'

总结一下:无论postgres还是mysql,一键恢复的功能,最好都是新起一个实例,然后把基础备份恢复上去,然后用binlog或wal归档日志进行恢复,然后导出数据,最后灌入到旧实例中,这样最稳妥,旧实例也不会停服务!!!


单机部署kafka用kraft不依赖zookeeper
上难度---->内网vps用lego申请route53 DNS证书并更新到BT宝塔
comments powered by Disqus