PostgreSQL 16 单虚拟机双实例部署及PITR时间点恢复实操
本文详细记录了在单台Ubuntu虚拟机上部署PostgreSQL 16双实例(main主库和test恢复库)并实现时间点恢复(PITR)的全过程。通过配置WAL归档、执行基础备份、插入测试数据等步骤,成功将test实例恢复至主库指定时间点状态。关键步骤包括:创建归档和备份目录、配置主库归档模式、执行基础备份、设置恢复参数以及最终将恢复库提升为独立实例。文章特别强调了archive_mode参数需重
本文记录在单台虚拟机上部署PostgreSQL 16双实例(main主库、test恢复库),并完成PITR(Point-in-Time Recovery,时间点恢复)的完整实操流程。
核心场景:单虚拟机内,通过两个PostgreSQL实例(main作为主库提供服务,test作为恢复库),实现主库备份、指定时间点恢复,最终将恢复库终止恢复、转为正常独立实例,模拟生产环境中数据恢复及实例切换的基础流程。(实际原因为我只有一台虚拟机)
一、环境说明
-
系统版本:Ubuntu(适配PostgreSQL 16)
-
PostgreSQL版本:16.13(Ubuntu 16.13-0ubuntu0.24.04.1)
-
实例规划:
-
main实例(主库):端口5432,用于数据存储、备份源
-
test实例(恢复库):端口5433,用于接收主库备份、完成时间点恢复
-
核心目录:
-
归档目录:/var/lib/postgresql/16/archive(存储WAL归档日志)
-
备份目录:/backup(存储主库基础备份文件)
-
实例数据目录:/var/lib/postgresql/16/main(main实例)、/var/lib/postgresql/16/test(test实例)
二、前期准备(创建目录并授权)
创建归档目录和备份目录,确保postgres用户拥有完整权限,避免后续备份、归档失败。
# 创建归档目录(用于存储WAL归档日志) postgres@lzy:~/16$ mkdir -p /var/lib/postgresql/16/archive # 创建备份目录(用于存储主库备份) postgres@lzy:~/16$ mkdir -p /backup # 授权postgres用户为目录所有者(PostgreSQL服务默认以postgres用户运行) postgres@lzy:~/16$ chown -R postgres:postgres /var/lib/postgresql/16/ # 授权postgres用户为备份目录所有者 postgres@lzy:~/16$ chown -R postgres:postgres /backup/
三、部署main主实例(主库)
创建main实例、启动服务,并配置WAL归档(需重启实例生效)。
# 创建main实例(PostgreSQL 16版本,实例名main) postgres@lzy:~/16$ pg_createcluster 16 main # 启动main实例 postgres@lzy:~/16$ pg_ctlcluster 16 main start # 开启归档模式(ALTER SYSTEM会将配置写入postgresql.auto.conf,永久生效) postgres@lzy:~/16$ psql -p 5432 -U postgres -c "ALTER SYSTEM SET archive_mode = on;" # 配置归档命令:先检查文件是否存在,避免重复归档,再将WAL文件复制到归档目录 postgres@lzy:~/16$ psql -p 5432 -U postgres -c "ALTER SYSTEM SET archive_command = 'test ! -f /var/lib/postgresql/16/archive/%f && cp %p /var/lib/postgresql/16/archive/%f';" # 重启main实例,使归档参数生效(archive_mode为静态参数,仅reload无法生效) postgres@lzy:~/16$ pg_ctlcluster 16 main restart
四、main主库基础备份
切换WAL日志,确保归档起点干净,然后执行在线基础备份(pg_basebackup不影响主库正常运行)。
# 切换WAL日志,生成新的WAL文件,确保归档目录有完整的日志起点 postgres@lzy:~/16$ psql -p 5432 -U postgres -c "select pg_switch_wal();" # 执行在线基础备份:端口5432(main实例),备份到/backup/full_backup,格式为tar压缩,同步获取WAL日志 postgres@lzy:~/16$ pg_basebackup -p 5432 -U postgres -D /backup/full_backup -F t -z -X fetch
五、main主库插入测试数据(用于验证恢复效果)
创建测试数据库、数据表,插入两组测试数据(数据A、数据B),并切换WAL日志确保数据归档,为后续时间点恢复做准备。
postgres@lzy:~/16$ psql -p 5432 -U postgres <<EOF DROP DATABASE IF EXISTS prod_data; CREATE DATABASE prod_data; \c prod_data; CREATE TABLE user_info(id int,name text,ctime timestamp); INSERT INTO user_info VALUES(1,'数据A',now()); SELECT now(); EOF NOTICE: database "prod_data" does not exist, skipping DROP DATABASE CREATE DATABASE You are now connected to database "prod_data" as user "postgres". CREATE TABLE INSERT 0 1 now ------------------------------- 2026-04-15 15:18:49.593855+00 (1 row) postgres@lzy:~/16$ psql -p 5432 -U postgres -c "select pg_switch_wal();" pg_switch_wal --------------- 0/4475300 (1 row) #插入数据B postgres@lzy:~/16$ psql -p 5432 -U postgres <<EOF \c prod_data; INSERT INTO user_info VALUES(2,'数据B',now()); EOF You are now connected to database "prod_data" as user "postgres". INSERT 0 1 postgres@lzy:~/16$ psql -p 5432 -U postgres -c "select pg_switch_wal();" pg_switch_wal --------------- 0/50000F0 (1 row) #再次查看数据 postgres@lzy:~/16$ psql -p 5432 -U postgres -d prod_data -c "SELECT * FROM user_info;" id | name | ctime ----+-------+---------------------------- 1 | 数据A | 2026-04-15 15:18:49.590541 2 | 数据B | 2026-04-15 15:19:20.942403 (2 rows)
六、部署test恢复实例
创建test实例,停止实例并清空其数据目录,为后续恢复主库备份做准备。
# 创建test实例(PostgreSQL 16版本,实例名test,默认端口5433) postgres@lzy:~/16$ pg_createcluster 16 test # 停止test实例(后续需清空数据目录,避免原有数据干扰恢复) postgres@lzy:~/16$ pg_ctlcluster 16 test stop # 清空test实例数据目录(确保恢复环境干净) postgres@lzy:~/16$ rm -rf /var/lib/postgresql/16/test/* # 解压main主库的基础备份,恢复到test实例数据目录 postgres@lzy:~/16$ tar -zxf /backup/full_backup/base.tar.gz -C /var/lib/postgresql/16/test/
七、test实例执行PITR时间点恢复
配置test实例的恢复参数,指定恢复时间点(介于数据A和数据B插入时间之间),启动恢复并验证恢复效果。
# 配置test实例的恢复参数(追加到postgresql.conf末尾) # restore_command恢复命令:从归档目录复制WAL日志到test实例的pg_wal目录 # recovery_target_time恢复目标时间:介于数据A插入时间15:18:49和数据B插入时间15:19:20之间 # 恢复完成后暂停,便于验证恢复结果 postgres@lzy:~/16$ cat >> /etc/postgresql/16/test/postgresql.conf <<EOF restore_command = 'cp /var/lib/postgresql/16/archive/%f %p 2>/dev/null || true' recovery_target_time = '2026-04-15 15:19:00' recovery_target_action = pause EOF # 创建恢复信号文件(PostgreSQL检测到该文件,会进入恢复模式) postgres@lzy:~/16$ touch /var/lib/postgresql/16/test/recovery.signal # 授权postgres用户为test实例目录所有者,避免权限不足 postgres@lzy:~/16$ chown -R postgres:postgres /var/lib/postgresql/16/test/ # 启动test实例,开始执行时间点恢复 postgres@lzy:~/16$ pg_ctlcluster 16 test start # 验证恢复结果:查看test实例的prod_data数据库,确认恢复情况 postgres@lzy:~/16$ psql -p 5433 -U postgres -d prod_data -c "SELECT * FROM user_info;" id | name | ctime ----+-------+---------------------------- 1 | 数据A | 2026-04-15 15:18:49.590541 (1 row) #查看test数据库在恢复状态 postgres@lzy:~/16$ pg_lsclusters Ver Cluster Port Status Owner Data directory Log file 16 main 5432 online postgres /var/lib/postgresql/16/main /var/log/postgresql/postgresql-16-main.log 16 test 5433 online,recovery postgres /var/lib/postgresql/16/test /var/log/postgresql/postgresql-16-test.log # 暂停WAL重放(恢复模式下,先暂停再执行提升) postgres@lzy:~/16$ psql -p 5433 -U postgres -c "select pg_wal_replay_pause();" # 提升test实例为主库,终止恢复模式(转为正常实例) postgres@lzy:~/16$ psql -p 5433 -U postgres -c "select pg_promote();"
八、注意事项
-
归档参数(archive_mode)为PostgreSQL静态参数,仅执行pg_reload_conf()无法生效,必须重启实例才能开启归档,若未重启,归档目录会为空,导致恢复失败。
九、总结
本文完成了单虚拟机上PostgreSQL 16双实例的部署、主库备份、PITR时间点恢复及恢复实例升主的完整实操,测试环境验证PITR恢复能力。核心关键点在于WAL归档的正确配置(需重启实例)、恢复时间点的准确设定。
更多推荐
所有评论(0)