最近因为工作需要,需要对PostgreSQL进行备份,之前仅是简单使用过,从未深入研究,而网上的一些分享文档也总是让我越看越晕,不得以看了PostgreSQL的官方文档,发觉这个功能还是很有意思的,在这里跟大家分享,以下所有内容是基于PostgreSQL11描写的。
pg有三种备份方案,分别是SQL快照备份、文件级别备份和持续存档备份。每个方案都是适合的场景,所以大家在项目中应用时,还是要充分了解各个方案的优缺点,下面分别介绍这三个方案。
就是使用工具生成一个数据库快照文件,当需要进行数据库恢复时,再使用工具将快照文件导入。
生成快照的工具是pg_dump和pg_dumpall,其中:
pg_dump命令只能备份一个数据库,不可以备份表空间、角色的定义,但可以指定表,并且,若生成文件过大,也可以使用压缩格式。基本命令如:pg_dump -f back_up.sql db_name
具体此命令的参数可以参考官方文档。
pg_dumpall命令可以备份数据库集群的全部内容,包含了表空间、角色的定义,这个命令是重新创建角色、表空间、空数据,然后再为每个数据库调用pg_dump。
快照恢复的工具是psql:
就是直接复制PostgreSQL用于在数据库中存储数据的文件。例如直接执行 tar -cf backup.tar /usr/local/pgsql/data;此方案仅适用于备份还原整个数据库集群,不支持单个表、库的备份还原。
1.方案简单便捷、易操作;
这个方案解决了前两个备份方案的不足,可以在不停止服务的前提下进行备份,并且可以持续备份。
其实本身PostgreSQL就会在pg_wal目录下存放预写式(WAL)日志,以保证系统崩溃后的安全。而关于WAL日志是什么,感兴趣的同学可以参照官方文档,就我所理解就是先顺序写WAL日志,然后再隔段时间将WAL日志刷到磁盘上,可以减少磁盘IO,而恢复时,即使数据还没有写入磁盘,也可以通过WAL日志进行恢复。
但是WAL日志不能无限写下去,如果一直写下去,磁盘不就写满了么,PostgreSQL有日志回滚机制,每个WAL日志段16M,最多能存放80M的日志,到达极限后,如若再生成新的日志段,就会覆盖之前旧的。基于这个原则,我们就没办法仅使用WAL日志进行备份。
而持续存档的方案就是,通过修改postgresql.conf配置,在后台持续将WAL日志段拷贝到更大的磁盘空间下,并手动定期进行数据基础备份,当进行完毕基础备份后,之前的WAL日志理论上就可以删除了,而在恢复时,可以只基于某个基础备份版本恢复,也可以基于时间点进行恢复。
主要涉及到三个参数:
wal_level = replica
archive_mode = on #修改此配置需重启服务
archive_command = 'test ! -f /var/lib/pgsql/backup_in_progress || (test ! -f /var/lib/pgsql/wal_backup/%f && cp %p /var/lib/pgsql/wal_backup/%f)'
归档命令archive_command,也可以是复杂的脚本,这完全基于各自的业务。例如,我希望在进行基础备份时,不要进行WAL日志的归档,以防止数据出错,并且归档时仅是同机器的拷贝,不计划跨机器,这个参数修改后,只需重新加载配置即可,并且不想使用归档功能后,若不想重启服务,直接设置archive_command=‘’即可
以下三种方式均可触发归档
pg提供了两个方式,一个是pg_basebackup工具,另一个是在命令行下执行命令。两个方式相同的是,都是在pg_wal目录下产生基础备份文件,并且进行归档,例如下图,执行备份后,生成000000010000000000000058文件和备份文件:
其中000000010000000000000058.00000060.backup中的前缀表示这个备份文件是以000000010000000000000058为基础进行的备份。而这个备份文件非常小,不用担心是否随着数据越来越多,备份文件也会越来越大。当进行完备份后,理论上就可以将这个备份以前的WAL日志进行删除了。
两种备份不同的是,第二种备份较第一种备份更加灵活,具体灵活在哪里,这里不多分享,可以参考文档
这里以第二种备份方案进行步骤描述:
首先,需要增加备份权限的角色,在命令行下执行:
create role repl nosuperuser replication login connection limit 32 encrypted password '111111';
其次,在配置文件pg_hba.conf中添加该角色的连接权限:
host replication repl 0.0.0.0/0 md5
最后, 执行脚本 backup.sh(实际使用时,要增加容错):
touch /var/lib/pgsql/backup_in_progress#防止进行基础备份时,系统进行WAL日志的归档
psql -c "select pg_start_backup('back_up_1st');"#开始备份,并为此次备份起名back_up_1st
tar -cf /var/lib/pgsql/backup.tar /var/lib/pgsql/11/data/#拷贝数据目录
psql -c "select pg_stop_backup();" #结束备份,可在备份目录下看到已生成备份文件
rm /var/lib/pgsql/backup_in_progress
tar -rf /var/lib/pgsql/backup.tar /var/lib/pgsql/wal_backup/#将备份期间产生的wal日志进行拷贝
到此,持续归档已完成,接下来是恢复过程。
pg_ctl stop
restore_command='cp /var/lib/pgsql/wal_backup/%f %p'
recovery_target_name='back_up_1st'#恢复到此版本
recovery_target = 'immediate'
postmaster.pid
postmaster.opts
忽略如下文件夹中的数据,但仍保留文件夹
pg_dynshmem/
pg_replslot/
pg_wal/
pg_notify/
pg_serial/
pg_snapshots/
pg_stat_tmp/
pg_subtrans/
/usr/pgsql-11/bin/postmaster -D /var/lib/pgsql/11/data/
至此,恢复步骤已完成
之前一直纠结于持续归档的原理,担心PostgreSQL的这个备份方案会过于粗糙,无法满足实际需要,研究一番发现,嗯,是我多虑了。文档很多地方写的很粗,PostgreSQL在很多细节其实支持的非常完善,以后慢慢补充。