在任何时间,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进行归档更高效,并且它们
将可以访问许多有用的服务器资源。有关归档模块的更多信息,请参见
Chapter 49。
当存档命令被信号终止(除了SIGTERM被用作服务器关闭的一部分)或者由于shell出现退出状态大于125的错误(比如命令未找到),或者如果存档功能发出ERROR
或FATAL
,存档进程将中止并由postmaster重新启动。在这种情况下,失败不会在pg_stat_archiver中报告。
归档命令和库通常应设计为拒绝覆盖任何已存在的归档文件。这是一个重要的 安全功能,用于在管理员错误的情况下(例如将两个不同服务器的输出发送到 同一归档目录)保护归档的完整性。建议测试您提议的归档库,以确保它不会 覆盖现有文件。
在极少数情况下,PostgreSQL可能会尝试重新归档
一个之前已经归档过的WAL文件。例如,如果系统在服务器对归档成功进行
持久记录之前崩溃,服务器将在重新启动后尝试再次归档该文件(前提是归档
功能仍然启用)。当归档命令或库遇到一个已存在的文件时,如果WAL文件的
内容与已存在的归档文件完全相同,并且已存在的归档文件已完全持久化到存储,
则它应分别返回零状态或true
。如果已存在的文件与正在归档的
WAL文件的内容不同,则归档命令或库必须分别返回非零状态或
false
。
上述用于 Unix 的示例命令通过包含一个单独的
test
步骤来避免覆盖已存在的归档文件。在某些 Unix 平台上,
cp
有一些如 -i
的开关,可以用来以更简洁的方式
实现相同的功能,但在未验证正确的退出状态返回之前,不应依赖这些开关。
(特别是,GNU cp
在使用 -i
且目标文件已存在时
会返回状态零,这不是期望的行为。)
在设计存档设置时,请考虑如果存档命令或库重复失败会发生什么,因为某些方面需要操作员干预或存档空间不足。例如,如果您在没有自动更换器的情况下写入磁带,则当磁带填满时,直到更换磁带为止,将无法再进行存档。您应确保任何错误条件或对人类操作员的请求都能得到适当报告,以便情况能够相对快速地得到解决。直到情况得到解决之前,pg_wal/
目录将继续填充WAL段文件。(如果包含pg_wal/
的文件系统填满,PostgreSQL将执行紧急关闭。不会丢失已提交的事务,但数据库将保持离线状态,直到释放一些空间。)
归档命令或库的速度并不重要,只要它能跟上服务器生成WAL数据的平均速率即可。即使归档过程稍微落后,正常操作仍将继续。
如果归档严重落后,这将增加在灾难事件发生时可能丢失的数据量。这也意味着pg_wal/
目录将包含大量尚未归档的段文件,这可能最终超过可用的磁盘空间。建议您监视归档过程,以确保其按照您的意图工作。
在编写存档命令或库时,应假定要存档的文件名最长可达64个字符,并且可以包含任何组合的ASCII字母、数字和点号。
不需要保留原始相对路径(%p
),但需要保留文件名(%f
)。
请注意尽管 WAL 归档允许你恢复任何对你的PostgreSQL数据库中数据所做的修改, 但它不会恢复对配置文件的修改(即postgresql.conf
、pg_hba.conf
以及pg_ident.conf
),因为这些文件都是手工编辑的,而不是通过 SQL 操作来编辑的。 所以你可能会需要把你的配置文件放在一个日常文件系统备份过程可处理的位置。如何重定位配置文件请参阅Section 19.2。
存档命令或函数仅在完成的WAL段上调用。因此,如果您的服务器生成的WAL流量很少(或者有间歇
期),在事务完成和安全记录到存档存储之间可能会有很长的延迟。为了限制未存档数据的
最旧时间,您可以设置archive_timeout,强制服务器至少在指定长的时间内切换
到新的WAL段文件。请注意,由于强制切换而提前存档的文件仍然与完全满文件相同长度。因此,
设置非常短的archive_timeout
是不明智的——它会使您的存档存储膨胀。
大约一分钟左右的archive_timeout
设置通常是合理的。
同样,如果你希望确保一个刚刚完成的事务能被尽快归档,可以使用pg_switch_wal
进行一次手动段切换。其他与WAL管理相关的使用函数在Table 9.95中列出。
当wal_level
为minimal
时,一些SQL命令会被优化以避免WAL日志记录,如Section 14.4.7中所述。
如果在执行这些语句期间打开了归档或流复制,WAL将不包含足够的信息用于归档恢复。(崩溃恢复不受影响。)
出于这个原因,wal_level
只能在服务器启动时更改。然而,archive_command
和archive_library
可以通过重新加载配置文件来更改。
如果您通过shell进行归档并希望暂时停止归档,一种方法是将archive_command
设置为空字符串(''
)。
这将导致WAL文件在pg_wal/
中积累,直到重新建立一个有效的archive_command
。
执行一次基础备份最简单的方法是使用pg_basebackup工具。它将会以普通文件或一个tar归档的方式创建一个基础备份。如果需要比pg_basebackup更高的灵活性,你也可以使用低级API(见Section 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段,如果这些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
)并执行恢复,
如 Section 25.3.5 中所述。恢复时需要较早备份并使用
pg_combinebackup
是在其他所有要求之外的额外要求。请记住,
PostgreSQL 没有内置机制来确定哪些备份仍然是恢复后续增量备份所需的基础。
您必须自行跟踪完整备份和增量备份之间的关系,并确保在恢复后续增量备份时不要删除可能需要的较早备份。
增量备份通常只适用于相对较大的数据库,这些数据库中有大量数据不会变化, 或者变化较慢。对于小型数据库,忽略增量备份的存在,直接进行完整备份更为 简单,且管理起来更方便。对于一个全部数据都被频繁修改的大型数据库,增量 备份的大小不会比完整备份小多少。
增量备份只有在重放将从比其依赖的上一次备份更晚的检查点开始时才可能进行。 如果您在主服务器上进行增量备份,则此条件始终满足,因为每次备份都会触发一个新的检查点。 在备用服务器上,重放从最近的重启点开始。因此,如果自上一次备份以来活动非常少, 备用服务器的增量备份可能会失败,因为可能没有创建新的重启点。
不使用pg_basebackup进行完整或增量基础备份时, 可以使用低级API进行基础备份。此过程比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)。 在执行此操作时,无需停止数据库的正常运行。参见Section 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
在最后一个段被归档之前不会返回。
在备机上,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会返回一个与致命错误无法区分的错误代码。幸运的是,如果一个文件在备份期间被改变,版本为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/
子目录中的文件通常也是个好主意,这样
主控机上存在的复制槽不会成为备份的一部分。否则,后续用该备份创建一个后备机可能会导致该
后备机上的WAL文件被无限期保留,并且在启用了热后备反馈的情况下可能导致主控机膨胀,因为使用
那些复制槽的客户端将继续连接到主控机(而不是后备机)并且继续更新其上的槽。即使该备份是要被
用来创建一个新的主控机,拷贝复制槽也不是特别有用,因为这些槽的内容在新主控机上线时很可能已
经过时。
目录pg_dynshmem/
、pg_notify/
、
pg_serial/
、pg_snapshots/
、
pg_stat_tmp/
和pg_subtrans/
的内容(但不包括这些目录本身)可以在备份中省略,因为它们将在postmaster启动时初始化。
任何以pgsql_tmp
开始的文件或目录都可以从备份中省略。这些文件在postmaster启动时会被移除,而目录将被根据需要重建。
只要找到名为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
中设置恢复配置参数(参见Section 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'
它将从目录/mnt/server/archivedir
中复制先前归档的WAL段。
当然,您可以使用更复杂的东西,甚至可能是一个shell脚本,
该脚本请求操作员挂载适当的磁带。
重要的是命令在失败时返回非零退出状态。该命令将被调用来请求不在归档中的文件, 在这种情况下它应该返回非零值。这不是一种错误情况。一种例外是该命令被一个信号(除了被用作数 据库服务器关闭动作一部分的SIGTERM)终止或者被shell的错误 (例如命令未找到)终止,那样恢复将中止并且服务器将不会启动。
并非所有被请求的文件都是WAL段文件,你也许还会请求一些具有.history
后缀的文件。还要注意的是,%p
路径的基本名字将会和%f
不同,但不要期望它们可以互换。
归档中找不到的WAL段可以在pg_wal/
中看到,这使得可以使用最近未归档的段。但是,在归档中可用的段将会被优先于pg_wal/
中的文件被使用。
通常,恢复将会处理完所有可用的WAL段,从而将数据库恢复到当前时间点(或者尽可能接近给定的可
用WAL段)。因此,一个正常的恢复将会以一个“文件未找到”消息结束,错误消息的准确文
本取决于你选择的restore_command
。你也可能在恢复的开始看到一个针对名称类
似于00000001.history
文件的错误消息。这也是正常的并且不表示在简单恢复情
况中的问题,对此的讨论见Section 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归档区域。历史文件是很小的文本文件,因此将它们无限期地保存起来的代价很小,而且也是很合适的(而段文件都很大)。如果你喜欢,你可以在一个历史文件中增加注释来记录如何和为什么要创建该时间线。当你由于试验的结果拥有了一大堆错综复杂的不同时间线时,这种注释将会特别有价值。
恢复的默认行为是沿着归档中所发现的最新的时间线进行恢复。如果你希望恢复到执行基础备份时的当前时间线或者某个指定的子时间线(即,你希望回到在一次恢复尝试后产生的某个状态),你需要指定current
或者在recovery_target_timeline中指定目标时间线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文件的总量。(在这样做之前,请阅读Chapter 28中的注释和
警告。)关闭页面快照不会阻止将WAL用于PITR操作。未来的一个开发方向是通过移除
不必要的页面副本来压缩归档的WAL数据,即使full_page_writes
已开启。在此期间,管理员可能希望通过尽可能增加检查点间隔参数来减少WAL中包含
的页面快照数量。