postgres备份恢复相关
25.3. 连续归档和时间点恢复(PITR) 摘自http://www.postgres.cn/docs/11/continuous-archiving.html
第一步建立wal归档
wal_level配置成replica或更高
archive_mode为on
配置archive_command,在archive_command
中,%p
会被将要归档的文件路径所替代,而%f
只会被文件名所替代(路径名是相对于当前工作目录而言的,即集簇的数据目录)。
archive_command = 'test ! -f /mnt/server/archivedir/%f && cp %p /mnt/server/archivedir/%f' # Unix
第二步,制作一个基础备份
可以用pg_basebackup工具,制作一个基础备份。
备份通过一个常规PostgreSQL连接制作,并且使用复制协议。该连接必须由一个超级用户或者一个具有REPLICATION
权限(第 21.2 节)的用户建立,并且pg_hba.conf
必须显式地允许该复制连接。该服务器还必须被配置,使max_wal_senders设置得足够高以留出至少一个会话用于备份以及一个用于WAL流(如果使用流)。
例子
要创建服务器mydbserver
的一个基础备份并将它存储在本地目录/usr/local/pgsql/data
中:
$
pg_basebackup -h mydbserver -D /usr/local/pgsql/data
要创建本地服务器的一个备份,为其中每一个表空间产生一个压缩过的 tar 文件,并且将它存储在目录backup
中,在运行期间显示一个进度报告:
$
pg_basebackup -D backup -Ft -z -P
要创建一个单一表空间本地数据库的备份并且使用bzip2压缩它:
$
pg_basebackup -D - -Ft -X fetch | bzip2 > backup.tar.bz2
(如果在该数据库中有多个表空间,这个命令将失败)。
要创建一个本地数据库的备份,其中/opt/ts
中的表空间被重定位到./backup/ts
:
$
pg_basebackup -D backup/data -T /opt/ts=$(pwd)/backup/ts
也可以使用低级api制作一个基础备份:
制作一个非排他低级备份:
1.确保wal归档被启用且正在工作。
2.用有运行pg_start_backup权力的用户连到服务器,发出命令: select pg_start_backup('label', false, false); #需要保持到备份结束。
第二个参数如果改为true,代表尽可能快地开始备份,将会发出一个立即的检查点并且使用尽可能多的io。
第三个参数如果改为true,表示要做一个非排他基础备份。
3.使用tar或者cpio执行备份。不需要停止正常的数据库操作。
确认你的备份包含数据库集簇目录(例如/usr/local/pgsql/data
)下的所有文件。如果你使用了不在此目录下的表空间,注意也把它们包括在内(并且确保你的备份将符号链接归档为链接,否则恢复过程将破坏你的表空间)。
排除pg_wal中的文件。
排除postmaster.pid和postmaster.opts
排除pg_replslot子目录中的文件
排除目录pg_dynshmem/
、pg_notify/
、pg_serial/
、pg_snapshots/
、pg_stat_tmp/
和pg_subtrans/
的内容,不过要保留他们的目录。
排除以pgsql_tmp开始的文件和目录
排除pg_internal.init的文件
4.在同一个连接中,发出命令: select * from pg_stop_backup(false); #这会终止备份模式。在主控机上,它还执行一次自动切换到下一个WAL段。
在后备机上,它无法自动切换WAL段,因此用户可能希望在主控机上运行pg_switch_wal
来执行一次手工切换。
要做切换的原因是让在备份期间写入的最后一个WAL段文件能准备好被归档。
pg_stop_backup
将返回一个具有三个值的行。这些域的 第二个应该被写入到该备份根目录中名为backup_label
的 文件。
第三个域应该被写入到一个名为tablespace_map
的文件,除非该域为空。这些文件对该备份正常工作来说是至关重要的, 不能被随意修改。
5.一旦备份期间活动的WAL段文件被归档,备份就完成了。由 pg_stop_backup
的第一个返回值标识的文件是构成一个 完整备份文件集合所需的最后一个段。在主控机上,如果archive_mode
被启用并且wait_for_archive
参数为true
,在最后一个段被归档之前pg_stop_backup
都不会返回。在后备机上,为了让pg_stop_backup
等待,archive_mode
必须为always
。从你已经配置好archive_command
之后这些文件的 归档就会自动发生。在大部分情况下,这些归档会很快发生,但是建议你监 控你的归档系统确保没有延迟。如果归档进程由于归档命令的失败而落后, 它将会持续重试知道归档成功并且备份完成。如果你希望对 pg_stop_backup
的执行给出一个时间限制,可以设置一个 合适的statement_timeout
值,但要注意如果 pg_stop_backup
因此而中止会致使备份可能失效。
25.3.4. 使用一个连续归档备份进行恢复
1.停止服务器
2.将整个数据库目录和表空间复制到一个临时位置。如果没有足够的空间,至少要保存集簇的pg_wal子目录的内容,因为它可能包含在系统垮掉之前还未被归档的日志。
3.移除所有位于集簇数据目录和正在使用的表空间根目录下的文件和子目录。
4.从文件系统备份中恢复数据库文件。注意用户权限。如果使用表空间,应该验证pg_tblspc中的符号链接被正确地恢复。
5.移除pg_wal中的任何文件,这些是来自于文件系统备份而不是当前日志,因此可以被忽略。
6.如果有在第2步中保存的未归档的wal段文件,把它们拷贝到pg_wal中
7.在集簇数据目录中创建要给恢复命令文件recovery.conf。你可能还想临时修改pg_hba.conf来阻止普通用户在成功恢复之前连接。
8.启动服务器。服务器将会进入到恢复模式并且进而根据需要读取归档WAL文件。恢复可能因为一个外部错误而被终止,可以简单地重新启动服务器,这样它将继续恢复。
恢复过程结束后,服务器将把recovery.conf
重命名为recovery.done
(为了阻止以后意外地重新进入恢复模式),并且开始正常数据库操作。
9.检查数据库的内容来确保你已经恢复到了期望的状态。如果没有,返回到第1步。如果一切正常,通过恢复pg_hba.conf
为正常来允许用户连接。
所有这些的关键部分是设置一个恢复配置文件,它描述你希望如何恢复以及恢复要运行到什么程度。你可以使用recovery.conf.sample
(通常在安装的share/
目录中)作为一个原型。你绝对必须在recovery.conf
中指定的是restore_command
,它告诉PostgreSQL如何获取归档WAL文件段。与archive_command
相似,这也是一个shell命令字符串。它可以包含%f
(将被期望的日志文件名替换)和%p
(将被日志文件被拷贝的目标路径名替换)。(路径名是相对于当前工作目录的,即集簇的数据目录)。如果你需要在命令中嵌入一个真正的%
字符,可以写成%%
。最简单的命令类似于:
restore_command = 'cp /mnt/server/archivedir/%f %p'
它将从目录/mnt/server/archivedir
中拷贝之前归档的WAL段。当然,你可以使用更复杂的,甚至是一个要求操作者装载合适磁带的shell脚本。
如果你希望恢复到之前的某个时间点(例如,恢复到幼稚的DBA丢弃了你主要的交易表之前),只需要 在recovery.conf
中指定要求的停止点。你可以使用日期/时间、命名恢复点或一个 指定事务ID的结束时间来定义停止点(也被称为“恢复目标”)。在这种写法中,只有日期/时 间和命名恢复点选项非常有用,因为没有工具可以帮助你准确地确定要用哪个事务ID。
25.3.5. 时间线
将数据库恢复到一个之前的时间点的能力带来了一些复杂性,这和有关时间旅行和平行宇宙的科幻小说有些相似。例如,在数据库的最初历史中,假设你在周二晚上5:15时丢弃了一个关键表,但是一直到周三中午才意识到你的错误。不用苦恼,你取出你的备份,恢复到周二晚上5:14的时间点,并上线运行。在数据库宇宙的这个历史中,你从没有丢弃该表。但是假设你后来意识到这并非一个好主意,并且想回到最初历史中周三早上的某个时间。你没法这样做,在你的数据库在线运行期间,它重写了某些WAL段文件,而这些文件本来可以将你引向你希望回到的时间。因此,为了避免出现这种状况,你需要将完成时间点恢复后生成的WAL记录序列与初始数据库历史中产生的WAL记录序列区分开来。
要解决这个问题,PostgreSQL有一个时间线概念。无论何时当一次归档恢复完成,一个新的时间线被创建来标识恢复之后生成的WAL记录序列。时间线ID号是WAL段文件名的一部分,因此一个新的时间线不会重写由之前的时间线生成的WAL数据。实际上可以归档很多不同的时间线。虽然这可能看起来是一个无用的特性,但是它常常扮演救命稻草的角色。考虑到你不太确定需要恢复到哪个时间点的情况,你可能不得不做多次时间点恢复尝试和错误,直到最终找到从旧历史中分支出去的最佳位置。如果没有时间线,该处理将会很快生成一堆不可管理的混乱。而有了时间线,你可以恢复到任何之前的状态,包括早先被你放弃的时间线分支中的状态。
每次当一个新的时间线被创建,PostgreSQL会创建一个“时间线历史”文件,它显示了新时间线是什么时候从哪个时间线分支出来的。系统在从一个包含多个时间线的归档中恢复时,这些历史文件对于允许系统选取正确的WAL段文件非常必要。因此,和WAL段文件相似,它们也要被归档到WAL归档区域。历史文件是很小的文本文件,因此将它们无限期地保存起来的代价很小,而且也是很合适的(而段文件都很大)。如果你喜欢,你可以在一个历史文件中增加注释来记录如何和为什么要创建该时间线。当你由于试验的结果拥有了一大堆错综复杂的不同时间线时,这种注释将会特别有价值。
恢复的默认行为是沿着相同的时间线进行恢复,该时间线是基础备份创建时的当前时间线。如果你希望恢复到某个子女时间线(即,你希望回到在一次恢复尝试后产生的某个状态),你需要在recovery.conf
中指定目标时间线ID。你不能恢复到早于该基础备份之前分支出去的时间线。
25.3.6. 建议和例子
这里将给出一些配置连续归档的建议。
25.3.6.1. 单机热备份
可以使用PostgreSQL的备份功能来产生单机热备份。这些备份不能被用于时间点恢复,然而备份和恢复时要比使用pg_dump转储更快(它们也比pg_dump转储更大,所以在某些情况下速度优势可能会被否定)。
在基础备份的帮助下,产生一个单机热备份最简单的方式是使用pg_basebackup工具。如果你在调用它时使用了-X
参数,使用该备份所需的所有事务日志将会被自动包含在该备份中,并且恢复该备份也不需要特殊的动作。
如果在复制备份文件时需要更多灵活性,也可以使用一个较低层的处理来创建单机热备份。要为低层 单机热备份做准备,确保wal_level
被设置为replica
或更高, archive_mode
设置为on
,并且设置一个archive_command
,该命令只当一个开关文件存在时执行归档。例如:
archive_command = 'test ! -f /var/lib/pgsql/backup_in_progress || (test ! -f /var/lib/pgsql/archive/%f && cp %p /var/lib/pgsql/archive/%f)'
该命令在/var/lib/pgsql/backup_in_progress
存在时执行归档,否则会安静地返回0值退出状态(让PostgreSQL能回收不需要的WAL文件)。
通过这样的准备,可以使用一个如下所示的脚本来建立备份:
touch /var/lib/pgsql/backup_in_progress psql -c "select pg_start_backup('hot_backup');" tar -cf /var/lib/pgsql/backup.tar /var/lib/pgsql/data/ psql -c "select pg_stop_backup();" rm /var/lib/pgsql/backup_in_progress tar -rf /var/lib/pgsql/backup.tar /var/lib/pgsql/archive/
开关文件/var/lib/pgsql/backup_in_progress
首先被创建,这使对于未完成WAL文件的归档操作发生。备份完成之后开关文件会被删除。归档的WAL文件则被加入到备份中,这样基础备份和所有需要的WAL文件都是同一个tar文件的组成部分。请记住在你的备份脚本中加入错误处理。