PostgreSQL的连续备份配置
需求定义
之前使用postgresql数据库备份是基于两种方式:一种是定期使用pg_dump作数据库的备份,另一种是用ZFS做硬盘快照备份。但是这两种方法都有其局限,前者在数据量大了以后太慢,后者的问题则是依赖于ZFS,而且也是有风险的。所以需要新的方案。
官方文档提供的方案是:基于WAL的连续归档。类似于我以前用过的ms sql或mysql的日志备份,提供了指定时间点恢复的能力。
实现方法
结合官方文档和GPT/Gemini的指导,备份和恢复需要以下步骤:
备份
- 启用WAL归档
- 生成基础备份(同时记录WAL中的检查点,以便未来使用WAL恢复),如有通过链接加入的表空间,也需要同时备份
- 备份WAL归档
恢复
- 停止服务
- 备份现有数据文件(特别是未归档的WAL)
- 删除现有数据文件(不要和上一步合来直接使用移动操作,以免出错导致数据不一致)
- 恢复基础备份(包括链接的表空间)
- 删除恢复出来的未归档WAL
- 恢复第二步备份的未归档WAL
- 配置postgresql.conf为恢复模式,从指定位置恢复归档过的WAL
- 启动服务,自动开始恢复(注意配置pg_hba.conf,禁止期间有不必要的数据库操作)
- 检查恢复结果
备份的具体配置
首先是启用WAL归档。修改postgresql.conf,加入以下内容:
archive_mode = on
archive_command = 'test ! -f /backup/archive_wal/%f && gzip < %p > /backup/archive_wal/%f && chmod g+r /backup/archive_wal/%f'
wal_level = replica
archive_timeout = 3600 # 每小时强制归档一次
其中的重点是archive_command,这里是一句shell命令,当它返回成功的时候,pgsql才会认为归档成功,并定期删除已归档成功的WAL。所以这里按官方文档作了一个测试,并且对要归档的WAL文件进行压缩。最后为了方便复制备份内容,加上了group的读权限,然后把复制备份的用户加入到postgres用户组(GID=70)中。
重启服务令这个配置生效后,准备做一个基础备份。
pg_basebackup -U postgres -h localhost -D /backup/$DBNAME -Ft -z -Xs -R
DBNAME变量为一个目录名,基础备份会在这里保存几个文件:包括数据库基础数据,未归档的WAL,以及一个描述文件记录校验信息等。参数中的-Ft -z
表示以tar.gz形式压缩备份,否则以数据库原始数据方式备份。-Xs
表示以stream方式记录WAL。-R
表示生成recovery.conf文件以便恢复。
最后将这个基础备份目录和前面配置的那个/backup/archive_wal/
中的归档WAL文件全部保存好即完成备份。
如果要定期重建基础备份的话,可以同时把旧的WAL归档删除以节约空间。
# 删除旧的基础备份
rm /backup/$(DBNAME)/*
if
pg_basebackup -U postgres -h localhost -D /backup/$(DBNAME) -Ft -z -Xs -R
then
# 必要时修改权限,以便其它用户复制备份
chown 1000:1000 /backup/${DBNAME}/*
# 基础备份成功则删除一天以前的WAL归档
find ${BAKWAL}/ -type f -mtime +1 -exec rm {} \;
else
# 基础备份失败则退出
echo "pg_basebackup fail"
exit 1
fi
恢复的具体操作
首先是停止现有服务并备份数据文件
systemctl stop postgresql
cp -R /var/lib/postgresql /var/backup/new
rm -r /var/lib/postgresql/*
恢复基础数据:
# 因为是使用压缩打包的格式,所以这里需要解压
cd /var/lib/postgresql
tar -xvf /var/backup/old/base.tar.gz
因为只恢复基础数据,不含WAL,所以可以略过删除未归档WAL的操作,如前面的备份中有未归档wal,则需要恢复过来:
cp -R /var/backup/new/pg_wal/* /var/lib/postgresql/pg_wal/
然后配置postgresql服务为恢复模式,修改postgresql.conf
,其中的路径是存放归档WAL的地方:
restore_command = 'gunzip -c /backup/archive_wal/%f > %p'
recovery_target_timeline = 'latest'
注意,因为之前归档WAL时使用了gzip压缩,此处需要解压出来恢复。
另外,如果这个WAL是备份过的,要注意一下文件权限,必须是postgres用户(UID=70)可读。
还有就是如果原来有archive wal配置要先去掉。
修改pg_hba.conf
,暂时禁止不必要的连接,然后启动postgresql服务:
systemctl start postgresql
最后检查一下恢复情况,日志里会显示恢复进度,直到恢复成功后即可停止服务,然后修改postgresql.conf
和pg_hba.conf
,恢复正常的配置,然后重启服务即可正常使用。
推送到[go4pro.org]