PostgreSQL管理—持续存档和时间点恢复 (PITR)
持续存档和时间点恢复 (PITR)
PostgreSQL在任何时候都在集群数据目录的子目录中维护一个预写日志(WAL) 。pg_wal/
日志记录对数据库数据文件所做的每一次更改。该日志的存在主要是出于安全的目的:如果系统崩溃,通过“重放”自上次检查点以来创建的日志条目,可以将数据库恢复到一致性。然而,日志的存在使得使用第三种策略备份数据库成为可能:我们可以将文件系统级备份与WAL文件的备份结合起来。如果需要恢复,我们将恢复文件系统备份,然后从备份的WAL文件中重放,使系统恢复到当前状态。与之前的两种方法相比,这种方法的管理更加复杂,但它有一些显著的好处:
- 我们不需要一个完全一致的文件系统备份作为起点。备份中的任何内部不一致都将通过日志重放来纠正(这与崩溃恢复期间发生的情况没有明显不同)。所以我们不需要文件系统快照功能,只需要tar或类似的归档工具。
- 由于我们可以将无限长的WAL文件序列组合起来进行重放,因此只需继续归档 WAL 文件即可实现连续备份。这对于大型数据库尤其有用,因为在这些数据库中可能不方便经常性的进行完整备份。
- 没有必要一直回放 WAL 条目。我们可以在任何时候停止重播,并获得数据库当时的一致快照。因此,该技术支持时间点恢复:可以在进行基本备份后的任何时间点将数据库恢复到其状态。
- 如果我们不断地将一系列 WAL 文件提供给另一台已经加载了相同基本备份文件的机器,我们就有了一个热备用系统:在任何时候我们都可以启动第二台机器,它会是一个几乎最新的副本数据库。
pg_dump和pg_dumpall不生成文件系统级备份,并且不能用作连续归档解决方案的一部分。这样的转储是合乎逻辑的,包含的信息不足以供WAL replay使用。
与普通文件系统备份技术一样,这种方法只能支持整个数据库集群的恢复,而不能支持子集的恢复。此外,它还需要大量的存档存储:基本备份可能非常庞大,繁忙的系统将产生大量必须存档的WAL流量。尽管如此,在许多需要高可靠性的情况下,它仍然是首选的备份技术。
要使用连续存档(许多数据库供应商也称为“在线备份”)成功恢复,您需要一系列连续的存档WAL文件,这些文件至少可以追溯到备份的开始时间。因此,在开始第一次备份之前,您应该设置并测试归档WAL文件的过程。因此,我们首先讨论归档WAL文件的机制。
设置 WAL 归档
从抽象意义上讲,运行的PostgreSQL系统会产生无限长的WAL记录序列。系统将该序列物理地划分为WAL段文件,每个文件通常为16MB(尽管段大小可以在initdb期间更改)。段文件的数字名称反映了它们在抽象序列中的位置。当不使用WAL归档时,系统通常只创建几个段文件,然后通过将不再需要的段文件重命名为更高的段号来“回收”它们。假设内容位于最后一个检查点之前的段文件不再受关注,可以循环使用。
在归档WAL数据时,我们需要在每个段文件被填充后捕获其内容,并在段文件被循环使用之前将该数据保存在某个位置。根据应用程序和可用硬件的不同,可能有许多不同的“将数据保存到某处”的方法:我们可以将段文件复制到另一台机器上的NFS挂载目录,将其写入磁带机(确保有一种方法来识别每个文件的原始名称),或者将它们批处理在一起并将它们刻录到 CD 上,或者其他备份保存方式。为了给数据库管理员提供灵活性,PostgreSQL尽量不对归档方式进行任何限制。相反,PostgreSQL允许管理员指定要执行的shell命令,以将完成的段文件复制到需要的任何地方。这个命令可以像cp一样简单,也可以调用复杂的shell脚本——这完全取决于你的心情。
要启用WAL存档,请将WAL_级别配置参数设置为“副本”或更高级别,将“存档”模式设置为“打开”,并指定要在“存档”命令配置参数中使用的shell命令。实际上,这些设置将始终放在postgresql中。conf文件。在archive_命令中,%p将替换为要存档的文件的路径名,而%f仅替换为文件名。(路径名相对于当前工作目录,即集群的数据目录。)如果需要在命令中嵌入实际的%字符,请使用%%。最简单有用的命令如下:
要启用 WAL 归档,请将wal_level
配置参数设置为replica
或higher
,将archive_mode
设置为on,并在archive_command
配置参数中指定要使用的 shell 命令。实际上,这些设置将始终放在postgresql.conf
文件中,在archive_command配置文件中,%p替换为要归档的文件的路径名,而%f仅替换为文件名。(路径名相对于当前工作目录,即集群的数据目录。)如果需要在命令中嵌入%字符,请使用%%。最简单有用的命令是这样的:
archive_command = 'test ! -f /mnt/server/archivedir/%f && cp %p /mnt/server/archivedir/%f' # Unix archive_command = 'copy "%p" "C:\\server\\archivedir\\%f"' # Windows
将可归档的WA段复制到目录/mnt/server/archivedir。(这只是一个例子,不是一个建议,可能不适用于所有平台。)替换%p和%f参数后,实际执行的命令可能如下所示:
test ! -f /mnt/server/archivedir/00000001000000A900000065 && cp pg_wal/00000001000000A900000065 /mnt/server/archivedir/00000001000000A900000065
将为每个要归档的新文件生成一个类似的命令。
存档命令将在运行PostgreSQL server的同一用户的所有权下执行。由于正在归档的一系列WAL文件实际上包含了数据库中的所有内容,因此您需要确保归档的数据不会被窥探;例如,归档到一个没有所属组或全局读取权限的目录中。
当且仅当存档命令成功时,它才返回零退出状态,这一点很重要。得到零结果后,PostgreSQL将假定该文件已成功存档,并将删除或回收该文件。然而,非零状态告诉PostgreSQL该文件没有被归档;它将定期重试,直到成功。
当归档命令被一个信号(不是用作数据库关闭的一部分的SIGTERM )或退出状态大于 125 的 shell 错误(例如未找到命令)终止时,归档进程将中止,并由postmaster
重新启动。在这种情况下,失败不会在pg_stat_archiver
中报告。
“归档”命令通常应设计为拒绝覆盖任何预先存在的存档文件。这是一项重要的安全功能,可以在管理员出错(例如将两台不同数据库的输出发送到同一个存档目录)时保护存档的完整性。
建议测试您编辑的归档命令,以确保它确实不会覆盖现有文件,并且在这种情况下返回非零状态。上面针对Unix的示例命令通过包含单独的测试步骤来确保这一点。在某些Unix平台上,cp具有诸如-i之类的开关,可用于不太详细地执行相同的操作,但是不应该在未验证返回正确的退出状态的情况下依赖这些开关。(尤其是,当使用-i并且目标文件已经存在时,cp将返回状态零,这不是期望的行为。)
在设计归档设置时,考虑如果存档命令重复失败会发生什么,因为某些方面需要管理员干预或归档空间不足。例如,如果在没有自动转换器的情况下写入磁带,就可能会发生这种情况;当磁带填满时,在交换磁带之前,不能再存档任何内容。您应确保向管理员报告错误情况或请求,以便能够合理快速地解决问题。pg_wal/
目录将继续填充wal段文件,直到情况得到解决。(如果包含pg_wal/的文件系统已满,PostgreSQL将紧急关闭。提交的事务不会丢失,但数据库将保持脱机状态,直到释放一些空间。)
归档命令的速度并不重要,只要它能够跟上数据库生成 WAL 数据的平均速率即可。即使归档过程稍有滞后,正常操作仍将继续。如果归档严重滞后,这将增加灾难发生时丢失的数据量。这还意味着pg_wal/
目录将包含大量尚未归档的段文件,这些文件最终可能会超出可用磁盘空间。建议您监控存档过程,以确保其按预期工作。
在编写归档命令时,您应该假设要归档的文件名最长为 64 个字符,并且可以包含 ASCII 字母、数字和点的任意组合。不必保留原始相对路径 ( %p
),但必须保留文件名 ( %f
)。
请注意,虽然WAL归档将允许您恢复对PostgreSQL数据库中的数据所做的任何修改,但它不会恢复对配置文件(即PostgreSQL.conf、pg_hba.conf和pg_ident.conf)所做的更改,因为这些文件是手动编辑的,而不是通过SQL操作。您可能希望将配置文件保存在将由常规文件系统备份过程备份的位置。
archive命令仅在已完成的WAL段上调用。因此,如果您的数据库只生成很少的WAL数据量(或者在产生WAL数据量时有空闲时间),那么从事务完成到在归档存储中安全记录之间可能会有很长的延迟。要限制未归档数据的保存时间,可以设置archive_timeout
,以强制数据库至少频繁地切换到新的WAL段文件。请注意,由于强制切换而提前归档的归档文件的长度仍然与完全完整的文件相同。因此,设置一个很短的archive_timeout
是不明智的——它会使存档存储空间膨胀。一分钟左右的archive_timeout
设置通常是合理的。
此外,如果您想确保尽快归档刚刚完成的事务,可以使用pg_switch_wal手动强制进行段切换。
当wal_level
设置我minimal
时,会优化一些SQL命令以避免wal日志记录。如果在执行其中一条语句时打开了存档或流式复制,WAL将无法包含足够的信息来进行存档恢复。(崩溃恢复不受影响。)因此,wal_level
只能在数据库启动时更改。但是,可以通过重新加载配置文件来更改archive_command
。如果希望暂时停止存档,一种方法是将archive_command
设置为空字符串 (’’)。这将导致WAL文件在pg_wal/
中累积,直到archive_command
重新建立起工作。
进行基本备份
执行基本备份的最简单方法是使用pg_basebackup工具。它可以将基本备份创建为常规文件或 tar 存档。如果需要比pg_basebackup提供的更大的灵活性,您还可以使用低级 API 进行基本备份。
不必担心进行基本备份所需的时间。但是,如果您通常在full_page_writes
禁用的情况下运行数据库,您可能会注意到在备份运行时性能下降,因为full_page_writes
在备份模式下实际上是强制打开的。
要使用备份,您需要保留在文件系统备份期间和之后生成的所有 WAL 段文件。为了帮助做到这一点,基本备份过程会创建一个备份历史文件,该文件会立即存储到 WAL 存档区域中。该文件以文件系统备份所需的第一个 WAL 段文件命名。例如,如果起始 WAL 文件是0000000100001234000055CD
备份历史文件,则将命名为0000000100001234000055CD.007C9330.backup
. (文件名的第二部分代表 WAL 文件中的确切位置,通常可以忽略。)一旦您安全地归档了文件系统备份和备份期间使用的 WAL 段文件(如备份历史文件中所指定),则不再需要名称数字较小的所有存档 WAL 段来恢复文件系统备份,并且可以将其删除。但是,您应该考虑保留多个备份集,以绝对确定您可以恢复数据。
备份历史文件只是一个小文本文件。它包含您给pg_basebackup的标签字符串,以及备份的开始和结束时间和WAL段。如果使用标签标识关联的转储文件,则存档的历史文件足以告诉您要恢复哪个转储文件。
由于您必须将所有存档的WAL文件保留到上一次基本备份,因此基本备份之间的间隔通常应根据您希望在存档的WAL文件上花费的存储量来选择。你也应该考虑你准备花多长时间来恢复,如果需要恢复的话,系统将不得不重放所有的WAL段,这可能需要一段时间,如果它已经很长一段时间以来的最后一个基础备份。
备份历史文件只是一个小文本文件。它包含您提供给pg_basebackup的标签字符串,以及备份的开始和结束时间和 WAL 段。如果使用标签来识别关联的转储文件,那么归档的历史文件就足以告诉您要恢复哪个转储文件。
由于您必须将所有已归档的 WAL 文件保留到您上次的基本备份,因此基本备份之间的间隔通常应根据您希望在已归档的 WAL 文件上花费多少存储空间来选择。您还应该考虑准备花多长时间进行恢复,如果需要恢复,那么系统将不得不重放所有的 WAL 段,如果自上次基本备份以来已经很长时间,那么恢复将相应的花费很长的时间。
使用低级 API 进行基本备份
使用低级API进行基本备份的过程比pg_basebackup方法包含更多步骤,但相对简单。按顺序执行这些步骤非常重要,并且在继续下一步之前验证步骤是否成功。
低级基本备份可以以非独占或独占的方式进行。建议使用非独占方法,独占方法不推荐使用,最终将被删除。
进行非独占低级备份
非独占低级别备份是指允许运行其他并发备份的备份(使用相同备份API启动的备份和使用pg_basebackup启动的备份)。
- 确保 WAL 存档已启用并正常工作。
- 以有权运行 pg_start_backup 的用户(超级用户或已被授予 EXECUTE 该功能的用户)连接到数据库(哪个数据库无关紧要),并发出以下命令:
SELECT pg_start_backup('label', false, false);
其中label
是用于唯一标识此备份操作的任何字符串。调用pg_start_backup
的连接必须保持到备份结束,否则备份将自动中止。
默认情况下,pg_start_backup
可能需要很长时间才能完成。这是因为它执行一个检查点,并且检查点所需的I/O将分散在很长一段时间内,默认情况下是检查点间隔的一半(请参阅配置参数checkpoint_completion_target)。这通常是您想要的,因为它将对查询处理的影响降至最低。如果希望尽快启动备份,请将第二个参数更改为true,这将使用尽可能多的I/O立即发出检查点。
第三个参数为false
时,pg_start_backup
将启动非独占的基本备份。
-
使用任何方便的文件系统备份工具(如tar或cpio,而不是pg_dump或pg_dumpall)执行备份。在执行此操作时,既没有必要也不希望停止数据库的正常操作。
-
在与以前相同的连接中,发出以下命令:
SELECT * FROM pg_stop_backup(false, true);
这将终止备份模式。在主节点上,它还会自动切换到下一个 WAL 段。在备节点上,无法自动切换 WAL 段,因此您可能希望pg_switch_wal
在主数据库上运行以执行手动切换。切换的原因是为了安排在备份间隔期间写入的最后一个 WAL 段文件准备归档。
pg_stop_backup
将返回一行三个值。第二个字段应写入备份根目录中名为backup_label
的文件。第三个字段应写入名为tablespace_map
的文件,除非该字段为空。这些文件对备份工作至关重要,必须逐字节写入,无需修改,这可能需要以二进制模式打开文件。
- 备份过程中活动的WAL段文件归档后,即可完成备份。
pg_stop_backup
的第一个返回值标识的文件是形成完整备份文件集所需的最后一段。在主节点上,如果archive_mode
启用且wait_for_archive
参数为true
,pg_stop_backup
则在最后一个段被归档之前不会返回。在备节点上,archive_mode
必须always
为pg_stop_backup
等待。由于您已经配置了archive_command
,这些文件的存档会自动进行归档。 在大多数情况下,这会很快发生,但建议您监控存档系统以确保没有延迟。如果归档进程由于归档命令失败而落后,它将继续重试,直到归档成功并且备份完成。如果您希望对pg_stop_backup
的执行设置时间限制,请设置适当的statement_timeout
值,但请注意,如果pg_stop_backup
因此终止,您的备份可能无效。
如果备份过程监控并确保备份所需的所有 WAL 段文件都已成功存档,则可以将wait_for_archive
参数(默认为true)设置为false,以便pg_stop_backup
在停止备份记录写入WAL后立即返回。默认情况下,pg_stop_backup
将等待所有 WAL 归档,这可能需要一些时间。必须谨慎使用此选项:如果未正确监控 WAL 归档,则备份可能不包括所有 WAL 文件,因此将不完整且无法恢复。
进行独占低级备份
独占备份方法已被弃用,应避免使用。在PostgreSQL 9.6之前,这是唯一可用的低级方法,但现在建议所有用户升级脚本以使用非独占备份。
独占备份的过程与非独占备份的过程基本相同,但在几个关键步骤上有所不同。这种类型的备份只能在主数据库上进行,不允许并发备份。此外,由于它会创建一个备份标签文件(如下所述),因此会在崩溃后阻止主数据库的自动重启。另一方面,从备份或备用文件中错误删除此文件是常见的错误,这可能会导致严重的数据损坏。如果需要使用这种方法,可以使用以下步骤。
独占备份的过程与非独占备份的过程基本相同,但在几个关键步骤上有所不同。这种类型的备份只能在主节点上进行,并且不允许并发备份。此外,因为它创建了一个备份标签文件(如下所述),所以它可以阻止主节点在崩溃后自动重启。另一方面,从备份或standby中错误地删除此文件是一个常见错误,这可能导致严重的数据损坏。如果需要使用该方法,可以使用以下步骤。
-
确保 WAL 归档已启用并正常工作。
-
以有权运行 pg_start_backup 的用户(超级用户或已被授予 EXECUTE 功能的用户)连接到数据库(哪个数据库无关紧要)并发出命令:
SELECT pg_start_backup('label');
其中
label
是要用于唯一标识此备份操作的任何字符串。pg_start_backup
在集群目录中创建一个名为 的备份标签文件,backup_label
其中包含有关您的备份的信息,包括开始时间和标签字符串。该函数还在集群目录中创建一个名为tablespace_map
的表空间映射文件,其中包含有关表空间符号链接的信息(pg_tblspc/
如果存在一个或多个此类链接)。如果您需要从中恢复,这两个文件对于备份的完整性都至关重要。默认情况下,
pg_start_backup
可能需要很长时间才能完成。这是因为它执行一个检查点,检查点所需的I/O将在相当长的一段时间内分散,默认情况下是检查点间隔的一半(请参阅配置参数checkpoint_completion_target)。这通常是您想要的,因为它将对查询处理的影响降至最低。如果要尽快启动备份,请使用:默认情况下,
pg_start_backup
可能需要很长时间才能完成。这是因为它执行一个检查点,并且检查点所需的 I/O 将分散在很长一段时间内,默认情况下是检查点间间隔的一半(请参阅配置参数checkpoint_completion_target
)。这通常是您想要的,因为它最大限度地减少了对查询处理的影响。如果您想尽快开始备份,请使用:SELECT pg_start_backup('label', true);
这将会使检查点尽快完成。
-
使用任何方便的文件系统备份工具(如tar或cpio,而不是pg_dump或pg_dumpall)执行备份。在执行此操作时,既没有必要也不希望停止数据库的正常操作。
如上所述,如果数据库在备份期间崩溃,则在
backup_label
手动从PGDATA
目录中删除文件之前,可能无法重新启动。请注意,在恢复备份时切勿删除backup_label
文件,因为这会导致数据损坏。混淆何时删除此文件是导致数据损坏的常见原因;务必确保仅在现有主设备上删除文件,而不是在构建备用数据库或恢复备份时删除该文件,即使您正在构建一个随后将被提升为新主数据库的备用数据库。 -
再次以有权运行 pg_stop_backup 的用户(超级用户,或已被授予 EXECUTE 功能的用户)连接到数据库,并发出命令:
SELECT pg_stop_backup();
此函数终止备份模式,并自动切换到下一个WAL段。切换的原因是为了在备份间隔期间写入的最后一个WAL段准备归档。
使用独占备份模式时,绝对必须确保pg_stop_备份在备份结束时成功完成。即使备份本身失败,例如由于磁盘空间不足,如果未能调用pg_stop_backup,数据库也会无限期地处于备份模式,导致未来的备份失败,并增加备份标签存在期间重启失败的风险。
-
备份过程中活动的WAL段文件归档后,即可完成备份。
pg_stop_backup
的结果所标识的文件是形成一套完整的备份文件集所需的最后一个段。如果archive_mode
启用,pg_stop_backup
则在最后一个段被归档之前不会返回。由于配置了archive_command
,这些文件将自动进行存档。在大多数情况下,这种情况发生得很快,但建议您监控存档系统以确保没有延迟。如果归档进程由于归档命令失败而落后,它将继续重试,直到归档成功并且备份完成。使用独占备份模式时,确保
pg_stop_backup
在备份结束时成功完成是绝对必要的。即使备份本身失败(例如由于磁盘空间不足),pg_stop_backup
调用失败也会使数据库无限期地处于备份模式,从而导致未来的备份失败,并增加在backup_label
存在的时间内重新启动失败的风险。
备份数据目录
如果在使用某些文件系统备份工具进行复制过程中,复制的文件发生了更改,则会发出警告或错误。在对活动数据库进行基本备份时,这种情况是正常的,而不是错误。但是,您需要确保能够区分此类complaints和真正的错误。例如,某些版本的rsync
会为“消失的源文件”返回一个单独的退出代码,您可以编写一个驱动程序脚,将此退出代码作为非错误情况接受。此外,如果在 tar复制文件时文件被截断,那么某些GNU版本的 tar返回的错误代码与致命错误无法区分。幸运的是,1.16及更高的GNU版本 tar在备份过程中如果文件发生更改,将以1退出,其他错误将以2退出。使用1.23 及更高的GNU版本的 tar ,您可以使用警告选项--warning=no-file-changed --warning=no-file-removed
来隐藏相关的警告消息。
确保您的备份包括数据库集群目录下的所有文件(例如,/usr/local/pgsql/data
)。如果您正在使用不在此目录下的表空间,请注意将它们也包括在内(并确保您的备份将符号链接存档为链接,否则恢复将损坏您的表空间)。
但是,您应该从备份中省略集群的pg_wal/
子目录中的文件。这种轻微的调整是值得的,因为它降低了恢复时出错的风险。如果pg_wal/
是指向集群目录之外某个位置的符号链接,这很容易理解,因为出于性能原因,这是一种常见的设置。您可能还想排除postmaster.pid
和postmaster.opts
,它记录有关正在运行的postmaster的信息,而不是关于最终将使用此备份的postmaster的信息。(这些文件可能会混淆pg_ctl。)
从备份中省略集群的pg_replslot/
目录中的文件通常是一个好主意,这样主数据库上的复制槽就不会成为备份的一部分。否则,后续使用备份创建standby可能会导致standby上无限期保留 WAL 文件,如果启用hot standby,则可能会导致主数据库上的WAL文件膨胀,因为使用这些复制槽的客户端仍将连接并更新主节点上的插槽,而不是standby节点上的插槽。即使备份仅用于创建新主节点,复制复制槽也不会特别有用,因为在新的主节点上线时,这些插槽的内容可能已经严重过时。
目录pg_dynshmem/
、pg_notify/
、pg_serial/
、pg_snapshots/
、pg_stat_tmp/
和pg_subtrans/
(但不是目录本身)的内容可以从备份中省略,因为它们将在 postmaster 启动时初始化。如果设置了stats_temp_directory,并且位于数据目录下,则该目录的内容也可以省略。
任何以pgsql_tmp
开头的文件或目录都可以从备份中省略。这些文件在postmaster 启动时被删除,并且将根据需要重新创建目录。
pg_internal.init
只要找到该名称的文件,就可以从备份中省略文件。这些文件包含在恢复时始终重建的关系缓存数据。
备份标签文件包括您提供给pg_start_backup
的标签字符串、pg_start_backup
的运行时间以及起始 WAL 文件的名称。因此,在出现混淆的情况下,可以查看备份文件内部并准确确定转储文件来自哪个备份会话。表空间映射文件包括存在于pg_tblspc/
目录中的符号链接名称以及每个符号链接的完整路径。这些文件不仅仅是供你参考的;它们的存在和内容对于系统恢复过程的正常运行至关重要。
也可以在数据库停止时进行备份。在这种情况下,显然不能使用pg_start_backup
或 pg_stop_backup
,因此您将被留在自己的设备上,以跟踪哪个备份是哪个备份以及相关WAL文件的备份时间。通常最好遵循上面的连续归档过程。
使用连续存档备份进行恢复
在最坏的情况已经发生后,你需要从备份中恢复。以下是恢复程序:
- 如果数据库正在运行,请停止数据库。
- 如果有空余的空间,请将整个集群数据目录和任何表空间复制到一个临时位置,以备不时之需。注意,此预防措施将要求您的系统上有足够的可用空间来保存现有数据库的两个副本。如果您没有足够的空间,您至少应该保存集群
pg_wal
子目录的内容,因为它可能包含在系统关闭之前未归档的日志。 - 删除集群数据目录下以及正在使用的任何表空间的根目录下的所有现有文件和子目录。
- 从文件系统备份中还原数据库文件。确保以正确的所有权(数据库系统用户,而不是
root
!)和正确的权限进行还原。如果正在使用表空间,则应验证pg_tblspc/
中的符号链接是否已正确还原。 - 删除
pg_wal/
中存在的所有文件;这些来自文件系统备份,因此可能已过时,而不是最新版本。如果您根本没有存档pg_wal/
文件,那么就使用适当的权限重新创建它,如果您之前用符号链接方式设置过,就需要确保将其重新建立为符号链接。 - 如果您在步骤 2 中保存了未归档的 WAL 段文件,请将它们复制到
pg_wal/
。(最好是复制它们,而不是移动它们,这样如果出现问题,你仍然有未修改的文件。) - 在
postgresql.conf
中设置恢复配置设置,并recovery.signal
在集群数据目录中创建一个文件。您可能还需要临时修改pg_hba.conf
以防止普通用户连接,直到您确定恢复成功。 - 启动数据库。数据库将进入恢复模式,并继续读取它需要的存档 WAL 文件。如果由于外部错误而终止恢复,则只需重新启动数据库,即可继续恢复。恢复过程完成后,数据库将删除
recovery.signal
(以防止以后意外地重新进入恢复模式),然后开始正常的数据库操作。 - 检查数据库的内容以确保您已恢复到所需的状态。如果没有,请返回步骤 1。如果一切正常,请通过恢复
pg_hba.conf
正常让用户连接。
所有这一切的关键部分是设置一个恢复配置,该配置描述了您希望恢复的方式以及恢复应该运行的距离。必须指定的是restore_command
,它告诉PostgreSQL如何检索归档的 WAL 文件段。和archive_command
一样,这是一个 shell 命令字符串。它可以包含%f
, 替换为所需日志文件的名称,以及%p
, 替换为要将日志文件复制到的路径名。(路径名相对于当前工作目录,即集群的数据目录。)如果需要在命令中嵌入实际的%字符,请写入%%。最简单有用的命令如下:
restore_command = 'cp /mnt/server/archivedir/%f %p'
它将从/mnt/server/archivedir
目录中复制以前存档的 WAL 段。当然,您想使用更复杂的东西,甚至可以使用一个shell脚本来请求装入适当的磁带。
重要的是,该命令在失败时返回非零退出状态。该命令将被称为请求归档中不存在的文件;当被询问时,它必须返回非零。这不是错误情况。例外情况是,如果命令被一个信号(SIGTERM除外,它用作数据库关闭的一部分)或 shell 的一个错误(例如找不到命令)终止的,则恢复将中止,数据库将不会启动。
并非所有请求的文件都是 WAL 段文件;您还应该期望对带有 . 后缀的文件的请求.history
。另请注意,%p
路径的基本名称将不同于%f
; 不要指望它们可以互换。
并非所有请求的文件都是 WAL 段文件;您还可以对带有 . 后缀的文件的请求,比如.history
。另请注意,%p
路径的基本名称将不同于%f
; 不要指望它们可以互换。
在归档中找不到的 WAL 段将在pg_wal/
; 这允许使用最近未归档的段。但是,归档中可用的段将优先于pg_wal/
.
通常情况下,恢复将通过所有可用的 WAL 段进行,从而将数据库恢复到当前时间点(或尽可能接近可用的 WAL 段)。因此,正常恢复将以“未找到文件”消息结束,错误消息的确切文本取决于您设置的restore_command
. 您可能还会在恢复开始时看到名为00000001.history
的文件。 这也是正常的,在简单的恢复情况下并不表示有问题;
如果您想恢复到以前的某个时间点(例如,就在初级DBA删除主事务表之前),只需指定所需的停止点。您可以通过日期/时间、还原点名称或特定事务ID的完成来指定停止点,称为“恢复目标”。其实只有日期/时间和命名还原点选项非常有用,因为没有工具可以帮助您准确地识别要使用的事务ID。
停止点必须在基础备份的结束时间之后,即
pg_stop_backup
的结束时间。您不能使用基本备份来恢复到该备份正在进行的时间。(要恢复到这样的时间,您必须回到以前的基本备份并从那里前滚。)
如果恢复发现损坏的WAL数据,恢复将在该点停止,服务器将不会启动。在这种情况下,恢复过程可以从头开始重新运行,在损坏点之前指定“恢复目标”,以便恢复可以正常完成。如果由于外部原因(如系统崩溃或WAL存档无法访问)而导致恢复失败,则可以简单地重新启动恢复,恢复将几乎从失败的地方重新启动。恢复重启的工作原理与正常操作中的检查点非常相似:服务器定期将其所有状态强制放到磁盘上,然后更新pg_控制文件,以指示不需要再次扫描已处理的WAL数据。
如果恢复发现损坏的 WAL 数据,恢复将在该点停止,并且数据库将不会启动。在这种情况下,恢复过程可以从头开始重新运行,在损坏点之前指定一个“恢复目标”,以便恢复可以正常完成。如果由于外部原因恢复失败(如系统崩溃或WAL存档无法访问),则可以简单地重新启动恢复,并且它将几乎从失败的地方重新启动。恢复重启的工作方式很像正常操作中的检查点:数据库定期其所有状态强制放到磁盘上,然后更新pg_control
文件,以指示不需要再次扫描已经处理的 WAL 数据。
时间线
将数据库恢复到以前的时间点的能力会产生一些类似于关于时间旅行和平行宇宙的科幻故事的复杂性。例如,在数据库的原始历史记录中,假设您在周二晚上 5:15 PM 删除了一个关键表,但直到周三中午才意识到自己的错误。毫不担心,您取出备份,恢复到周二晚上 5:14 PM 的时间点,然后开始运行。在这个数据库宇宙的历史,你从来没有删除过表。但是假设您后来意识到这不是一个好主意,并想回到原始历史中的某个星期三早上。如果在您的数据库启动并运行时,它会覆盖一些 WAL 段文件,这些文件会影响您现在希望可以返回的时间,那么您将无法做到这一点。因此,为避免这种情况,您需要将在执行时间点恢复后生成的一系列 WAL 记录与在原始数据库历史记录中生成的记录区分开来。
为了解决这个问题,PostgreSQL有一个时间线的概念. 每当归档恢复完成时,都会创建一个新的时间线来识别在该恢复之后生成的一系列 WAL 记录。时间线 ID 号是 WAL 段文件名的一部分,因此新时间线不会覆盖先前时间线生成的 WAL 数据。事实上,可以归档许多不同的时间线。虽然这似乎是一个无用的功能,但它通常是救命稻草。考虑一下您不太确定要恢复到哪个时间点的情况,因此必须通过反复试验进行多次时间点恢复,直到找到从旧历史分支的最佳位置。如果没有时间表,这个过程很快就会产生无法控制的混乱局面。使用时间线,您可以恢复到任何先前的状态,包括您之前放弃的时间线分支中的状态。
每次创建新的时间线时,PostgreSQL都会创建一个“时间线历史”文件,显示它从哪个时间线分支以及何时分支。当从包含多个时间线的存档中恢复时,这些历史文件是允许系统选择正确的 WAL 段文件所必需的。因此,它们就像 WAL 段文件一样被归档到 WAL 归档区。历史文件只是小文本文件,因此将它们无限期地保存起来既便宜又合适(与大的段文件不同)。如果愿意,您可以在历史文件中添加评论,以记录您自己关于如何以及为何创建此特定时间线的注释。当您通过实验获得大量不同的时间线时,此类评论将特别有价值。
恢复的默认行为是沿进行基本备份时的当前时间线进行恢复。如果您希望恢复到某个子时间线(即,您希望返回到恢复尝试后自身生成的某个状态),您需要在recovery.conf中指定目标时间线 ID 。您无法恢复到早于基本备份分支的时间线。
提示和示例
此处提供了一些配置连续归档的技巧。
独立热备份
如果需要更灵活地复制备份文件,也可以将较低级别的过程用于独立热备份。要准备低级别的独立热备份,请确保wal_level设置为“副本”或更高级别,archive_mode设置为“打开”,并设置一个archive_命令,。例如:
可以使用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
存在时,此命令将执行归档,否则将以静默方式返回零退出状态(允许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/
首先创建switch 文件/var/lib/pgsql/backup_in_progress
,以便归档已完成的WAL文件。备份后,将删除switch文件。然后将归档的 WAL 文件添加到备份中,以便基本备份和所有必需的 WAL 文件都属于同一个tar文件。请记住在备份脚本中添加错误处理。
压缩存档日志
如果需要考虑归档存储大小,可以使用gzip压缩归档文件:
archive_command = 'gzip < %p > /mnt/server/archivedir/%f.gz'
然后,您将需要在恢复期间使用gunzip :
restore_command = 'gunzip < /mnt/server/archivedir/%f.gz > %p'
Archive_command
脚本
很多人选择使用脚本来定义他们的archive_command
,以便postgresql.conf
条目看起来非常简单:
archive_command = 'local_backup_script.sh "%p" "%f"'
每当您想在归档过程中使用多个命令时,建议使用单独的脚本文件。这允许在脚本中管理所有复杂性,脚本可以用流行的脚本语言编写,例如bash或perl。
可能在脚本中解决的需求示例包括:
- 复制数据以保护异地数据存储
- 批处理 WAL 文件,以便每三个小时传输一次,而不是一次传输一个
- 与其他备份和恢复软件的接口
- 与监控软件接口以报告错误
提示
使用archive_command
脚本时,最好启用logging_collector
。然后,从脚本写入stderr的任何消息都将出现在数据库服务器日志中,如果复杂配置失败,则可以轻松诊断它们。
注意事项
在本文中,连续归档技术存在一些限制。这些可能会在未来的版本中修复:
- 如果在进行基本备份时执行
CREATE DATABASE
命令,然后在基本备份仍在进行时修改了CREATE DATABASE
复制的模板数据库,则恢复可能会导致这些修改也传播到创建的数据库中. 这当然是不可取的。为避免这种风险,最好不要在进行基本备份时修改任何模板数据库。 CREATE TABLESPACE
命令使用文字绝对路径进行 WAL 记录,因此将作为具有相同绝对路径的表空间创建重放。如果在另一台机器上重放日志,这可能是不可取的。即使日志在同一台机器上重放,但将其放在新的数据目录中,也可能很危险:重放仍然会覆盖原始表空间的内容。为避免此类潜在问题,最佳实践是在创建或删除表空间后进行新的基本备份。
还应该注意的是,默认的WAL格式相当庞大,因为它包含许多磁盘页面快照。这些页面快照旨在支持崩溃恢复,因为我们可能需要修复部分写入的磁盘页面。根据您的系统硬件和软件,部分写入的风险可能小到可以忽略,在这种情况下,您可以通过使用full_page_writes
参数关闭页面快照来显着减少归档日志的总量。关闭页面快照不会阻止将日志用于 PITR 操作。未来发展的一个领域是通过删除不必要的页面副本来压缩存档的 WAL 数据,即使在full_page_writes
开启。同时,管理员可能希望通过尽可能增加检查点间隔参数来减少 WAL 中包含的页面快照的数量。
翻译自:[26.3. Continuous Archiving and Point-in-Time Recovery (PITR)](https://www.postgresql.org/docs/14/continuous-archiving.html)