研究了Postgres的库数据恢复和转移,再来研究一下PITR按时间点恢复
类比到MySQL,因为我们是运维,不是专业的DBA,所以恢复到正确数据即可
那跟阿里云以及自建的MySQL恢复一样,首先都要有一个每天的基础备份,然后类比MySQL的Binlog,Postgres这里就相当于wal。
这么类比就对了,那么恢复过程的思路是一样的:
- 首先建立一个新的实例
- 第二步把每天的基础物理全备给恢复上去
- 第三步把之后的wal日志传到新实例,恢复到指定时间点
- 第四步最后把表或库Dump下来,灌入到旧实例的新表或新库
那我们一步一步来解释:
一、每天建立一个基础备份,这样在Base基础上,只需恢复当天的wal,速度够快
建立每天的Base基础物理备份
pg_basebackup -Ft -Pv -Xf -z -Z5 -U postgres -h localhost -p 5432 -D /pg_backup
解释一下:
-Ft:
指定备份格式为 tar。
如果使用 tar 格式,备份会输出 tar 文件,并且不需要直接访问 PostgreSQL 数据目录。
-Pv:
-P:显示备份进度。
-v:启用详情模式(verbose),显示更多日志。
-Xf:
-X:控制 WAL 日志的处理方式,f 表示在备份中包含 WAL 文件(Write Ahead Logs),确保备份可以用于恢复到完整的一致状态。
-z:
启用压缩功能。
-Z5:
设置压缩级别为 5(压缩级别从 0 到 9,9 为最高压缩)。
-U postgres:
使用 postgres 用户来连接数据库。
-h localhost:
指定数据库主机为当前机器(localhost)。
-p 5432:
指定 PostgreSQL 监听端口为 5432(默认端口)。
-D /pg_backup:
将备份文件保存到指定路径 /pg_backup 中。
这样我们就在 /pg_backup 中有了备份文件,包括一个backup_manifest的文件清单,以及一个压缩包
root@debian:/pg_backup# ls -lha
total 1.8G
drwxr-xr-x 3 root root 4.0K Jul 28 16:31 .
drwxr-xr-x 20 root root 4.0K Jul 28 16:18 ..
-rw------- 1 root root 760K Jul 28 16:21 backup_manifest
-rw------- 1 root root 1.8G Jul 28 16:21 base.tar.gz
那这个base.tar.gz里面又都有什么呢?
/
├── base/ # 每个数据库的文件
├── global/ # 全局对象(角色、权限)
├── pg_wal/ # WAL 日志
├── pg_xact/ # 事务状态
├── pg_clog/ # 事务提交信息
├── postgresql.auto.conf # 自动配置文件
├── postgresql.conf # 主配置文件
├── pg_hba.conf # 访问控制文件
├── pg_ident.conf # 用户映射文件
└── ... # 其他系统文件
我们先 ps axjf 看一把

可以看到,-D的数据目录是在/var/lib/postgresql/13/main下,那base.tar.gz里面的内容跟/var/lib/postgresql/13/main下是一样的。
二、旧实例需要建立wal的归档模式
# ps axjf的结果中,看到配置文件是 /etc/postgresql/13/main/postgresql.conf
# 那就修改这个配置文件
# 修改以下2行
# 启用归档
archive_mode = on
# WAL 日志归档路径
archive_command = 'cp %p /path_to_archive_directory/%f'
# 然后重启服务生效
systemctl restart postgresql
以上做完后我们如果我们做了Base备份,然后wal的日志还在继续跑,那我们就需要手动触发一下wal写盘
select pg_switch_wal();
pg_switch_wal
---------------
0/13DAC308
会得到一个序列号:0/13DAC308
然后新的wal归档日志就放在:/path_to_archive_directory/目录下了,那原始的wal数据文件还在 /var/lib/postgresql/13/main/pg_wal 下
三、新实例恢复Base库和时间点:
# 找到新实例的数据目录,一把删空,然后把base.tar.gz解压进去
# 建恢复目录并清理旧数据
# 将解压后的备份移到数据库实例的实际数据目录(通常位于 /var/lib/postgresql/data)。清理旧目录后执行:
mv /pg_restore/ /var/lib/postgresql/data
# 设置恢复配置文件
# 在数据目录中创建一个名为 recovery.signal 的空文件,同时在数据目录中新增恢复目标的配置文件 postgresql.auto.conf。
touch recovery.signal
#编辑或创建文件 postgresql.auto.conf:
vi /var/lib/postgresql/data/postgresql.auto.conf
# 添加以下内容:
# 旧实例的wal文件需要事先copy到新实例的 /path_to_archive_directory 目录下
primary_conninfo = ''
restore_command = 'cp /path_to_archive_directory/%f %p'
recovery_target_time = 'YYYY-MM-DD HH:MI:SS'
recovery_target_action = 'pause'
说明:
restore_command:用于指定如何恢复 WAL 日志。这里的命令是从归档目录 /path_to_archive_directory/ 中拷贝 WAL 日志到 PostgreSQL 数据目录。
recovery_target_time:你希望恢复到的时间点精确到秒(UTC 时间)。
recovery_target_action:在完成恢复到目标时间后,pause 表示暂停恢复并进入只读模式
然后开始恢复:
# 确保 PostgreSQL 数据目录已准备好,删除目录下旧的 postmaster.pid 等文件:
rm /var/lib/postgresql/data/postmaster.pid
# 启动 PostgreSQL 服务:
systemctl start postgresql
# 确认恢复进度
# 观察 PostgreSQL 的日志文件(通常位于 /var/log/postgresql/postgresql-X.log,具体路径根据配置文件可能不同):
tail -f /var/log/postgresql/postgresql-X.log
# 如果一切正常,你应该能看到以下内容:
consistent recovery point reached at 0/16B6F98
recovery stopping at specified recovery target
# 退出恢复模式
mv /var/lib/postgresql/data/standby.signal /var/lib/postgresql/data/standby.signal.bak
# 退出恢复模式后,确认是只读模式
SELECT pg_is_in_recovery();
# 如果要进入可读可写的模式
select pg_wal_replay_resume();
四、dump出新实例指定表或库的数据,然后灌回旧实例的新表或新库
这个过程就不多说了。
多说一句,可以恢复到某个时间点,事务或者wal序列号
# 恢复到不同时间点
# 假设第一次恢复后,你希望尝试恢复到另一个时间点,修改 postgresql.auto.conf 文件中的 recovery_target_time 然后同样重复以上步骤即可重新恢复。
recovery_target_time = 'YYYY-MM-DD HH:MI:SS'
# 以某个事务为目标:
recovery_target_xid = '12345'
#以某个 WAL 日志序列号为目标:
recovery_target_lsn = '0/16B6F98'
总结一下:无论postgres还是mysql,一键恢复的功能,最好都是新起一个实例,然后把基础备份恢复上去,然后用binlog或wal归档日志进行恢复,然后导出数据,最后灌入到旧实例中,这样最稳妥,旧实例也不会停服务!!!