在任何时候,PostgreSQL 都会在集群数据目录的 pg_wal/
子目录中保留一个预写日志 (WAL)。该日志会记录对数据库数据文件所做的每一次更改。该日志主要用于保证系统在崩溃之后正常工作:如果系统崩溃,可以通过“重放”上一次检查点以来所做的日志条目来将数据库恢复到一致的状态。但是,该日志的存在使得可以使用第三种策略来备份数据库:我们可以将文件系统级备份与 WAL 文件备份结合在一起。如果需要恢复,我们会还原文件系统备份,然后从备份的 WAL 文件中重放来使系统恢复为当前状态。与任何一种前述方法相比,这种方法在管理方面更为复杂,但它也有一些显著的好处
我们并不需要一个完全一致的文件系统备份作为起点。备份中的任何内部不一致性都将会通过日志重放得到更正(这与崩溃恢复期间发生的情况并无明显不同)。所以我们并不需要文件系统快照功能,只需要 tar 或类似的归档工具即可。
由于我们可以合并无限长的 WAL 文件序列以进行重放,因此只需继续归档 WAL 文件即可实现连续备份。对于大型数据库而言,特别有价值,因为可能不方便频繁地进行完全备份。
没有必要一直重放 WAL 条目直到最后。我们可以在任何一点停止重放,并获得当时的一致数据库快照。因此,这种技术支持按时间点恢复:有可能将数据库恢复到自基本备份以来任何时间的某个状态。
如果我们持续将一系列 WAL 文件提供给已加载了相同的基本备份的其他机器,那么我们就会拥有一个预热备用系统:在任何一点我们都可以启用第二台机器,而且它都将拥有数据库的近似当前副本。
pg_dump 和 pg_dumpall 不会生成文件系统级别的备份,并且不可用作连续归档解决方案的一部分。这些转储是 逻辑 的,不包含足够的信息来供 WAL 回放使用。
与普通的文件系统备份技术一样,此方法只能支持整个数据库集群的还原,不支持子集还原。此外,它需要大量的归档存储:基本备份可能很庞大,并且繁忙的系统将生成许多兆字节的 WAL 流量,必须归档这些流量。不过,在需要高可靠性的许多情况下,它仍是首选的备份技术。
要使用连续归档(许多数据库供应商也将其称为 “联机备份”)成功恢复,你需要一段连续的归档 WAL 文件序列,它至少要延伸到你备份开始时间。因此,在进行第一次基本备份之前,你应设置并测试归档 WAL 文件的过程。因此,我们首先讨论归档 WAL 文件的机制。
从抽象意义上说,正在运行的 PostgreSQL 系统会产生一段无限长的 WAL 记录序列。该系统将此序列实际划分为 WAL 段文件,每个段文件通常为 16MB(尽管可以在 initdb 期间更改段大小)。将为段文件指定数字名称,反映它们在抽象 WAL 序列中的位置。不使用 WAL 归档时,系统通常只创建几个段文件,然后通过将不再需要的段文件重命名为更高的段号来 “回收” 它们。我们假设内容早于上次检查点的段文件不再重要,可以回收。
归档 WAL 数据时,我们需要在填充每个段文件后捕获其内容,并在为重用回收段文件前将这些数据保存在某个位置。根据应用程序和可用硬件,可能有多种 “将数据保存在某个位置” 的方法:我们可以将段文件复制到另一台计算机上的 NFS 挂载目录中,将它们写入磁带驱动器(确保你有办法识别每个文件的文件名),或者将它们批量打包并刻录到 CD 上,或其他完全不同的方式。为了为数据库管理员提供灵活性,PostgreSQL 尝试不对如何进行归档做出任何假设。相反,PostgreSQL 允许管理员指定 shell 命令或归档库,以便在完成段文件后将其执行,并将其复制到需要放置的任何位置。这可以简单到使用 cp
的 shell 命令,或者可以调用一个复杂的 C 函数,这完全取决于你。
如需启用 WAL 存档,请将 wal_level 配置参数设置为 replica
或更高,将 archive_mode 设置为 on
,在 archive_command 配置参数中指定要使用的 shell 命令,或在 archive_library 配置参数中指定要使用的库。实际上,这些设置始终会放置在 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
该命令将会把可归档 WAL 段复制到目录 /mnt/server/archivedir
。(这是一个示例,而非建议,并且可能无法在所有平台上运行。)替换 %p
和 %f
参数后,执行的实际命令可能如下所示
test ! -f /mnt/server/archivedir/00000001000000A900000065 && cp pg_wal/00000001000000A900000065 /mnt/server/archivedir/00000001000000A900000065
对于将要归档的每个新文件,系统都会生成一个类似的命令。
存档命令将在与 PostgreSQL 服务器相同的用户所有权下执行。由于正在归档的 WAL 文件系列实质上包含数据库中的所有内容,因此您需要确保归档数据免于窥探;例如,将存档数据归档到没有组或世界读取权限的目录中。
需要注意的是,只有在存档命令成功执行的情况下,该命令才会返回零退出状态。在获得零结果后,PostgreSQL 将假定该文件已成功归档,并将删除或回收该文件。但是,非零状态会告诉 PostgreSQL 该文件未归档;系统将在成功之前定期重试。
另一种存档方式是使用自定义存档模块作为 archive_library
。由于此类模块是用 C
编写的,因此创建您自己的模块可能需要比编写 shell 命令多得多的精力。但是,存档模块的性能可能比通过 shell 进行存档更高,并且可以访问许多有用的服务器资源。有关存档模块的详细信息,请参阅 第 49 章。
当归档命令被信号终止(除作为服务器关机的一部分而使用的 SIGTERM 之外),或者由 shell 发出的错误带有大于 125 的退出状态(例如未找到命令),或如果归档函数发出 ERROR
或 FATAL
,归档器进程将中止并由 postmaster 重新启动。在这种情况下,故障不会在 pg_stat_archiver 中报告。
归档命令和库通常应设计为拒绝覆盖任何预先存在的归档文件。这是一项重要的安全功能,旨在在管理员错误(例如将两台不同服务器的输出发送到同一个归档目录)的情况下保留归档的完整性。建议您测试建议的归档库以确保它不会覆盖现有文件。
在极少数情况下,PostgreSQL 可能会尝试重新归档之前已归档的 WAL 文件。例如,如果服务器在对归档成功记录持久化之前系统崩溃,则服务器将在重新启动后尝试再次归档该文件(前提是仍启用归档)。当归档命令或库遇到现有文件时,如果 WAL 文件与已存在的归档具有相同的内容且已存在的归档已完全持久化到存储,则它应分别返回零状态或 true
。如果既存文件与正归档的 WAL 文件包含不同的内容,则归档命令或库 必须 分别返回非零状态或 false
。
上面针对 Unix 的示例命令通过包含一个单独的 test
步骤来避免覆盖现有归档。在某些 Unix 平台上,cp
具有诸如 -i
的开关,可以使用它以不那么冗长的方式来做同样的事情,但您不应依赖这些开关,除非验证是否返回了正确的退出状态。(尤其,如果使用 -i
并且目标文件已存在,GNU cp
将返回状态零,而这 并非 所需行为。)
在设计归档设置时,请考虑如果归档命令或库因某些方面需要操作员干预或归档空间用尽而反复失败将发生什么情况。例如,如果在没有自动更换机的条件下写入磁带时可能会发生这种情况;当磁带已满时,在磁带更换之前无法再完成归档。应确保妥善报告任何错误条件或对操作员的要求,以便可以相对快速地解决该情况。pg_wal/
目录将继续填充 WAL 段文件,直到该情况得到解决为止。(如果包含 pg_wal/
的文件系统已满,PostgreSQL 将执行 PANIC 关机。不会丢失已提交的事务,但数据库仍将保持脱机状态,直到您释放一些空间。)
只要归档命令或库的速度能跟上服务器生成 WAL 数据的平均速度,那么其速度并不重要。即使归档过程略有延迟,正常操作仍会继续。如果归档大幅落后,这将增加在发生灾难时丢失的数据量。这还意味着 pg_wal/
目录将包含大量尚未归档的段文件,这最终可能会超过可用的磁盘空间。建议您监控归档过程,以确保其按照预期工作。
在编写归档命令或库时,应假定要归档的文件名长度最长可达 64 个字符,并且可以包含 ASCII 字母、数字和句点的任意组合。无需保留原始相对路径 (%p
),但必须保留文件名 (%f
)。
请注意,虽然 WAL 归档将允许您恢复对 PostgreSQL 数据库中的数据所做的任何修改,但它不会恢复对配置文件所做的更改(即 postgresql.conf
、pg_hba.conf
和 pg_ident.conf
),因为这些文件是通过手动方式编辑的,而不是通过 SQL 操作编辑的。您可能希望将配置文件保存在常规文件系统备份程序将备份的位置中。请参阅第 19.2 节,了解如何重新定位配置文件。
存档命令或功能仅在已完成的 WAL 段上调用。因此,如果服务器仅仅生成少量的 WAL 流量(或者在这样做的过程中存在闲置时间),那么事务完成与其在存档存储中被安全记录的时间之间可能会出现一段较长的延迟。为限制未存档数据的时效,你可以设置archive_timeout 以迫使服务器至少在指定的时间间隔内切换至新的 WAL 段文件。请注意,由于强制切换而提前存档的文件仍与已完全填满的文件一样长。因此,不建议设置很短的archive_timeout
— 它会增大你的存档存储。通常来讲,大约一分钟的archive_timeout
设置是合理的。
另外,如果你希望确保刚刚完成的事务尽快存档,你可以使用pg_switch_wal
手动强制执行一个段切换。有关 WAL 管理的其他实用程序函数列于表格 9.95中。
当wal_level
为minimal
时,某些 SQL 命令经过优化以避免 WAL 日志记录,如第 14.4.7 节中所述。如果在执行其中一个语句期间启用了归档或流复制,那么 WAL 中不会包含足够的信息以用于归档恢复。(故障恢复不受影响。)由于此原因,wal_level
只能在服务器启动时更改。但是,archive_command
和archive_library
可以通过重新加载配置文件来更改。如果你正通过 shell 进行归档并希望暂时停止归档,那么一种办法是将archive_command
设为一个空字符串(''
)。这会导致 WAL 文件逐渐累积在pg_wal/
中,直到重新建立一个可用的archive_command
。
执行基础备份的最简单方法是使用pg_basebackup工具。它可以将基础备份创建为常规文件或 tar 存档。如果需要比pg_basebackup所能提供的更灵活的功能,还可以使用低级 API 来创建基础备份(参见第 25.3.4 节)。
无需担心创建基础备份所花费的时间。但是,如果你通常禁用了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 通过指定 --incremental
选项,来执行增量备份。您必须将备份清单提供给 --incremental
作为参数,清单源自相同服务器的早期备份。在生成的备份中,非关联文件将完整包含,但是某些关联文件可能被更小的增量文件替换,其仅包含自上次备份后更改的块和足够元数据,足以重建当前文件版本。
为了找出哪些块需要备份,服务器使用 WAL 摘要,该摘要存储在数据目录中 pg_wal/summaries
目录的内部。如果所需的摘要文件不存在,将尝试执行增量备份,但会失败。此目录中存在的摘要必须涵盖从先前的备份开始 LSN 到当前备份开始 LSN 的所有 LSN。由于服务器在建立当前备份的开始 LSN 之后才寻找 WAL 摘要,因此所需的摘要文件可能不会立即出现在磁盘上,但服务器将等待任何缺失文件出现。如果 WAL 摘要进程落后,这也将有所帮助。但是,如果已经删除必要的摘要文件,或者 WAL 摘要器不足够快地赶上,则增量备份将失败。
在恢复增量备份时,除了增量备份本身之外,还需要所有早期备份,以提供增量备份中遗漏的块。有关此要求的详细信息,请参见 pg_combinebackup。请注意,更改集群的校验和状态时,对 pg_combinebackup
的使用有使用限制;请参见 pg_combinebackup 限制。
请注意,使用完全备份的所有要求也适用于增量备份。例如,您仍然需要文件系统备份期间及之后生成的所有 WAL 片段文件和任何相关的 WAL 历史文件。并且您仍然需要创建一个 recovery.signal
(或 standby.signal
)并执行恢复,如第 25.3.5 部分所述。除了其他所有内容之外,还有在恢复时必须有较早备份可用并使用 pg_combinebackup
的要求。请记住,PostgreSQL 没有任何内置机制来弄清楚哪些备份仍然可用作还原稍后的增量备份的基础。您必须自行跟踪完全备份和增量备份之间的关系,并确保在还原稍后的增量备份时不删除较早的备份。
增量备份通常只对不经常更改或仅缓慢更改的数据量较大的数据库有意义。对于较小的数据库,比较简单的方法是忽略增量备份的存在,直接进行完全备份,管理起来更容易。对于数据量很大且全部经过大量修改的数据库,增量备份不会比完全备份小很多。
只有当恢复从较新的检查点开始,而不是从当前备份所依赖的较旧检查点开始时,增量备份才有可能。如果您在主数据库上进行增量备份,则此条件总是满足,因为每个备份都会触发一个新的检查点。在备用数据库上,恢复从最新的重新启动点开始。因此,如果自上次备份以来几乎没有活动,则备用服务器的增量备份可能会失败,因为可能没有创建新的重新启动点。
您可以使用 low-level API 创建基础备份,而不是使用 pg_basebackup 来进行完全或增量基础备份。此过程比使用 pg_basebackup 方法多几个步骤,但相对简单。非常重要的是按顺序执行这些步骤,并在继续执行下一步骤之前验证步骤是否成功。
可以同时运行多个备份(使用此备份 API 启动的备份和使用 pg_basebackup 启动的备份)。
确保 WAL 归档已启用并正常工作。
作为有权运行 pg_backup_start
(超级用户或已授予此函数 EXECUTE
权限的用户)的用户连接到服务器(与连接哪个数据库无关),并发出命令
SELECT pg_backup_start(label => 'label', fast => false);
其中 label
是您想用于唯一标识此备份操作的任何字符串。调用 pg_backup_start
的连接必须保持到备份结束,否则备份将被自动中止。
在线备份总是从检查点的开始处启动。默认情况下,pg_backup_start
将等待下一个定期计划的检查点完成,这可能需要很长时间(请参阅配置参数 checkpoint_timeout 和 checkpoint_completion_target)。这样做通常是首选,因为它可以最大程度地降低对运行系统的的影响。如果您希望尽快开始备份,请将 true
作为第二个参数传递给 pg_backup_start
,它将请求一个立即检查点,该检查点将尽可能快地完成,并使用尽可能多的 I/O。
使用任何方便的文件系统备份工具(如 tar 或 cpio(而非 pg_dump 或 pg_dumpall))执行备份。在执行此操作时,无需也不愿意停止数据库的正常操作。有关在本备份期间需要考虑的事项,请参阅 第 25.3.4.1 节。
在与之前相同的连接中,发出以下命令
SELECT * FROM pg_backup_stop(wait_for_archive => true);
此命令将终止备份模式。在主服务器上,它还将自动切换到下一个 WAL 段。在备用服务器上,无法自动切换 WAL 段,因此您可能希望在主服务器上运行 pg_switch_wal
以执行手动切换。切换的原因是安排在备份期间写入的最后一个 WAL 段文件准备好归档。
pg_backup_stop
将返回一行,其中有三个值。这些字段中的第二个应写入备份根目录中名为 backup_label
的文件中。除非该字段为空,否则应将第三个字段写入一个名为 tablespace_map
的文件。这些文件对备份工作至关重要,并且必须逐字节写入,不得修改,这可能需要以二进制模式打开文件。
归档完备份期间激活的 WAL 段文件后,你就结束任务了。pg_backup_stop
的第一个返回值被确认的文件是形成一组完整的备份文件所需的最后一个段。对于主数据库,如果启用 archive_mode
,并且 wait_for_archive
参数为 true
,那么 pg_backup_stop
不会在 letzte 片段被存档之前返回。对于备用数据库,archive_mode
必须为 always
,以便 pg_backup_stop
等待。这些文件的归档会自动发生,因为你已经配置了 archive_command
或 archive_library
。在大多数情况下,此操作都会很快发生,但是建议你监控归档系统以确保没有延迟。如果归档进程因归档命令或库的故障而落后,那么进程将一直重试,直到归档成功且备份完成。如果你希望限制 pg_backup_stop
的执行时间,请设置一个合适的 statement_timeout
值,但请注意,如果 pg_backup_stop
因为此原因而终止,那么你的备份可能无效。
如果备份进程监控并确保备份所需的所有 WAL 段文件都已成功归档,则可以将 wait_for_archive
参数(默认为 true)设置为 false,以便在停止备份记录被写入 WAL 时让 pg_backup_stop
返回。默认情况下,pg_backup_stop
将等待所有 WAL 已归档,此过程可能需要一些时间。使用此选项时必须小心:如果 WAL 归档未得到正确监控,则备份可能不会包括所有 WAL 文件,因而备份将不完整且无法还原。
如果备份过程中所尝试复制的文件被更改,某些文件系统备份工具会发出警告或错误。为活动数据库获取基本备份时,这属于正常情况,不是错误。但是,你需要确保能够将此类抱怨与真正错误区分开来。例如,某些版本的 rsync 为 “消失的源文件” 返回单独的退出代码,你可以编写一个驱动脚本以将此退出代码接受为非错误案例。另外,如果在 tar 复制文件时该文件被截断,某些版本的 GNU tar 会返回与致命错误无法区分的错误代码。幸运的是,如果在备份过程中更改了文件,GNU tar 版本 1.16 及更高版本将退出并显示 1,对于其他错误将显示 2。对于 GNU tar 版本 1.23 及更高版本,你可以使用警告选项 --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/
目录内的文件是个好主意,以便主服务器上存在的复制槽不会成为备份的一部分。否则,以后使用备份来创建备用服务器时,可能会导致备用服务器上的 WAL 文件无限期保留,并且如果启用了热备反馈,则由于使用这些复制槽的客户端仍会连接到主服务器并更新其上的槽而不是备用服务器,从而在主服务器上造成膨胀。即使备份仅打算用于创建新的主服务器,复制槽的内容在新的主服务器上线时仍然可能非常过时,因此复制槽的内容复制预计并不是特别有用。
目录 pg_dynshmem/
、pg_notify/
、pg_serial/
、pg_snapshots/
、pg_stat_tmp/
和 pg_subtrans/
(但不是目录本身)的内容可以从备份中省略,因为它们将在启动后初始化。
以 pgsql_tmp
开头的任何文件或目录都可以从备份中省略。这些文件在启动时删除并且将根据需要重新创建目录。
每当找到该名称的文件时,都可以从备份中省略 pg_internal.init
文件。这些文件包含在恢复时始终重新构建的关系缓存数据。
备份标签文件包括您向 pg_backup_start
提供的标签字符串,以及运行 pg_backup_start
的时间和起始 WAL 文件的名称。因此,在出现混淆的情况下,可以查看备份文件内部并准确确定转储文件来自哪次备份会话。表空间映射文件包括符号链接名称,这些名称存在于目录 pg_tblspc/
中,和各个符号链接的完整路径。这些文件不止是供您参考;它们的出现和内容对系统恢复流程的正确操作至关重要。
也可以在服务器已停止时进行备份。在这种情况下,您显然无法使用 pg_backup_start
或 pg_backup_stop
,因此您将不得不自己记录哪个备份是哪个以及相关的 WAL 文件回溯多久。一般来说,最好遵循上述连续归档步骤。
好的,最糟糕的情况已经发生,您需要从备份中恢复。以下是过程
停止服务器(如果正在运行)。
如果您可以这样做,请将整个群集数据目录和任何表空间复制到临时位置,以备以后需要。请注意,此预防措施需要您的系统有足够的可用空间来容纳现有数据库的两个副本。如果您没有足够的空间,至少应保存群集的 pg_wal
子目录的内容,因为它可能包含在系统宕机前尚未归档的 WAL 文件。
删除群集数据目录和正在使用的任何表空间的根目录下所有现有的文件和子目录。
如果您要还原完全备份,则可以将数据库文件直接还原到目标目录。确保使用正确的属主(数据库系统用户,而不是 root
!)和正确的权限来还原它们。如果您正在使用表空间,则应验证 pg_tblspc/
中的符号链接是否已正确还原。
如果您要还原增量备份,则需要将增量备份及其直接或间接依赖的所有早期备份还原到执行还原操作的计算机。这些备份需要放置在单独的目录中,而不是要将正在运行的服务器放置到的目标目录。完成后,使用 pg_combinebackup 从完全备份和所有后续增量备份中提取数据,并将合成完全备份写入目标目录。如上所述,确认权限和表空间链接正确无误。
删除 pg_wal/
中存在的任何文件;这些文件来自文件系统备份,因此可能是过时的而不是最新的。如果您根本没有对 pg_wal/
进行归档,那么使用适当的权限重新创建它,如果您以前是以这种方式设置的,请小心确保重新将其建立为符号链接。
如果您在步骤 2 中保存了未归档的 WAL 段文件,请将它们复制到 pg_wal/
。(最好复制它们,而不是移动它们,这样在出现问题以及您必须重新开始时,您仍然拥有未修改的文件。)
\在 postgresql.conf
中设置恢复配置项(详见章节 19.5.5),并在群集数据目录中创建一个recovery.signal
文件。你还可以暂时修改 pg_hba.conf
,以防普通用户在恢复完成之前建立连接。
启动服务器。服务器会进入恢复模式,并继续读取所需的已归档 WAL 文件。如果恢复因为外部错误而终止,只需重启服务器,即可继续恢复。恢复流程完成后,服务器将删除 recovery.signal
(以防误重新进入恢复模式),然后开始正常的数据库操作。
检查数据库内容,确保已恢复到所需状态。如果不正确,请返回第 1 步。如果一切正常,则恢复 pg_hba.conf
为正常,允许你的用户建立连接。
最重要的一点是设置恢复配置,该配置描述如何恢复以及恢复应运行到什么程度。必须明确指定的一点是 restore_command
,它会告诉 PostgreSQL 如何检索已归档的 WAL 文件段。与 archive_command
一样,这也是一个 Shell 命令字符串。它可以包含 %f
,会被所需 WAL 文件的名称替换;可以包含 %p
,会被该 WAL 文件的路径名替换(路径名相对于当前工作目录,即群集的数据目录)。如果需要在命令中嵌入实际的 %
字符,则应编写 %%
。最简单有用的命令类似于
restore_command = 'cp /mnt/server/archivedir/%f %p'
这会将先前提出的 WAL 段从目录 /mnt/server/archivedir
。当然,你可以使用更复杂的方法,甚至可以使用一个 shell 脚本来请求操作员加载合适的磁带。
需要注意,命令在执行失败时应返回一个非零退出状态。该命令会被调用,以请求归档中不存在的文件;在被要求这样做时,它必须返回非零结果。这不属于错误情况。例外情况是:如果该命令由一个信号(SIGTERM 除外,SIGTERM 用作数据库服务器关闭的一部分)或 Shell 错误(如命令未找到)终止,那么恢复将会中止,服务器也不会启动。
并非所有请求的文件都是 WAL 段文件;你应该准备好接受后缀为 .history
的文件请求。此外,还要注意,%p
路径的基本名称将不同于 %f
;不要指望它们可以互换。
无法在归档中找到的 WAL 片段将在 pg_wal/
中搜索;这允许使用最近未归档的片段。但是,来自归档的片段将优先于 pg_wal/
中的文件。
通常情况下,将继续执行所有可用的 WAL 片段的恢复,从而将数据库恢复到当前时间点(或尽可能接近可用的 WAL 片段)。因此,正常恢复将以 “找不到文件” 消息结束,确切的错误消息文本取决于您选择的 restore_command
。您还可以在恢复开始时看到一个错误消息,用于名为 00000001.history
的文件。这也很正常,不会在简单的恢复情况下指示问题;有关讨论,请参见 第 25.3.6 节。
如果您想恢复到某个之前的时间点(比如,在年轻的 DBA 删除您的主事务表之前的正确时间),只需指定所需的 停止点。您可以通过日期/时间、指定的恢复点或完成特定事务 ID 来指定停止点,即所谓的 “恢复目标”。在撰写本文时,只有日期/时间和指定的恢复点选项才非常可用,因为没有任何工具可以帮助您准确识别要使用的事务 ID。
停止点必须在基本备份的结束时间之后,即 pg_backup_stop
的结束时间之后。您无法使用基本备份恢复到该备份正在进行中的时间。(要恢复到该时间,您必须返回到上一个基本备份并从此处向前滚动。)
如果恢复过程中检测到损坏的 WAL 数据,恢复将会在该点停止,服务器将不会启动。在该情况下,可以从头重新运行恢复处理,指定损坏点之前的““恢复目标””,以便恢复可以正常完成。如果恢复因外部原因(比如系统崩溃或无法访问 WAL 存档)而失败,则可以简单地重新启动恢复,并且该恢复将从其失败的点接近重新启动。恢复重启在处理方式上很像正常操作中的检查点:服务器定期将所有状态强制写入磁盘,然后更新pg_control
文件,以指示不需要再次扫描已处理的 WAL 数据。
将数据库恢复到先前时间点的功能形成了一些复杂性,这些复杂性类似于关于时间旅行和平行宇宙的科幻故事。例如,在数据库的原始历史中,假设你在星期二下午 5:15 删除了一个关键表,但直到星期三中午才意识到自己的错误。毫不气馁地拿出备份,恢复到星期二下午 5:14 的时间点,而且正在正常运行。在这个数据库宇宙的历史中,你从没有删除过该表。但是,假设你后来意识到这并不是一个好主意,而且希望返回到原始历史中的星期三某个时间点。在数据库正常运行时,如果它覆盖了一些导至你现在希望返回的时间的 WAL 段文件,则你将无法做到。因此,为了避免这种情况,你需要区分在时间点恢复之后生成的一系列 WAL 记录与在原始数据库历史中生成的 WAL 记录。
为了解决此问题,PostgreSQL有一个时间线的概念。只要存档恢复完成,就会创建一个新时间线来标识该恢复之后生成的一系列 WAL 记录。时间线 ID 号是 WAL 段文件名的一部分,因此新时间线不会覆盖以前时间线生成 WAL 数据。例如,在 WAL 文件名0000000100001234000055CD
中,开头的00000001
是十六进制时间线 ID。(请注意,在其他上下文中,例如服务器日志消息,时间线 ID 通常以十进制打印。)
事实上,有可能归档许多不同的时间线。虽然这看起来可能像一个无用的功能,但它通常能救命。考虑一下这种情况:不确定恢复到哪个时间点,因此必须通过反复试验进行几次时间点恢复,直到找到从旧历史中分支的最佳位置。如果没有时间线,此过程很快就会产生一个难以管理的混乱局面。使用时间线,可以恢复到任何先前状态,包括先前放弃的时间线分支中的状态。
每次创建新时间线时,PostgreSQL都会创建一个“时间线历史”文件,该文件显示了它从哪个时间线分支出来的,以及什么时候。恢复包含多个时间线的归档时,系统需要这些历史文件才能选择正确的 WAL 段文件。因此,它们就像 WAL 段文件一样归档到 WAL 归档区域。历史文件只是小的文本文件,因此保留它们无论多久都是低成本且合适的(与大型段文件不同)。如果愿意,可以向历史文件添加注释,以记录有关如何和为何创建此特定时间线自己的笔记。当由于实验而产生了许多不同的时间线时,这种注释将特别有价值。
恢复的默认行为是恢复到归档中找到的最新时间线。如果希望恢复到在获取基础备份时为当前时间线或恢复到特定子时间线(即,希望返回在恢复尝试后自身生成的状态),则需要在 recovery_target_timeline 中指定current
或目标时间线 ID。无法恢复到早于基础备份分支的时间线。
这里提供了一些用于配置连续归档的提示。
可以使用 PostgreSQL 的备份工具来生成单独热备份。这些备份无法用于时间点恢复,但通常比 pg_dump 转储速度快得多。(它们也比 pg_dump 转储大得多,因此在某些情况下,速度优势可能被否定。)
与基本备份一样,生成独立热备份最简单的方法是使用 pg_basebackup 工具。如果你在其调用中加入 -X
参数,则用于备份的所有预写式日志将自动包含在该备份中,并且无需任何特殊操作就可以还原该备份。
如果担心归档存储大小,则可以使用 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 时,这可能不是理想的结果。即使在同一机器上重播 WAL 时,但进入到新的数据目录中,这也会存在危险:重播仍将覆盖原始表空间的内容。为了避免此类潜在陷阱,可在创建或删除表空间后执行一次新的基本备份,这是最理想的做法。
还应该注意,由于包含许多磁盘页面快照,因此默认的WAL格式相对庞大。这些页面快照旨在支持崩溃恢复,因为我们可能需要修复部分写入的磁盘页面。根据你的系统硬件和软件,部分写入的风险可能小到可以忽略不计。在这种情况下,可以通过使用 full_page_writes 参数关闭页面快照,从而显著减少存档的 WAL 文件的总量。(执行此操作之前,阅读 第 28 章 中的注释和警告。)关闭页面快照不会妨碍使用 WAL 进行 PITR 操作。未来开发的一个领域是,即使在 full_page_writes
为启用状态时,也通过删除不必要的页面副本对存档的 WAL 数据进行压缩。与此同时,管理员可能希望通过尽可能地增加检查点间隔参数,来减少 WAL 中包含的页面快照数量。