pgsql.cc 提供对 postgresql.org 官网内容的中文翻译,由 Pigsty 团队维护。
持续归档可用于创建一种高可用性(HA)集簇配置,其中有一个或多个备库随时准备在主库失效时接管操作。这种能力通常称为温备或日志传送。
主库和备库协同工作以提供这种能力,不过两者之间只是松耦合。主库运行在持续归档模式下,而每台备库都运行在持续恢复模式下,从主库读取 WAL 文件。启用这种能力不需要对数据库表做任何更改,因此与其他一些复制方法相比,它的管理开销较低。这种配置对主库的性能影响也相对较小。
将 WAL 记录直接从一台数据库服务器移动到另一台数据库服务器,通常称为日志传送。PostgreSQL实现的是基于文件的日志传送,也就是说 WAL 记录每次传送一个文件(一个 WAL 段)。WAL 文件(16MB)可以容易且廉价地传送到任何距离之外,无论是相邻的系统、同一站点的另一系统,还是完全不同站点上的另一系统。这种技术所需的带宽取决于主库服务器的事务率。通过自行开发的过程也可以实现基于记录的日志传送,相关讨论见第 24.4.4 节。
应当注意,日志传送是异步的,即 WAL 记录在事务提交之后才被传送。因此,一旦主库发生灾难性故障,就存在一个数据丢失窗口;尚未传送的事务将会丢失。基于文件的日志传送的丢失窗口由归档间隔决定,归档间隔可以用archive_timeout来部分控制(如果没有归档超时,就完全由 WAL 段大小决定)。丢失窗口可以通过参数设置来降低,但它始终存在。
恢复性能已经足够好,因此一旦备库被激活,通常只需片刻就能达到完全可用状态。因此,这种配置被称为温备配置,它提供了高可用性。从归档的基础备份中恢复服务器并向前重放 WAL,这一能力与持续恢复结合在一起,就得到了温备。可以看到,与基于记录的日志传送方案相比,基于文件的日志传送所需的定制开发要少得多。
通常,最好让主库和备库尽可能相似,至少从数据库服务器的角度看应如此。尤其是,与表空间相关的路径名会原样传递,因此如果使用该特性,主库和备库必须为表空间配置完全相同的挂载路径。请记住,如果在主库上执行 CREATE TABLESPACE,则它所需的任何新挂载点都必须在执行该命令之前先在主库和所有备库上创建好。硬件不必完全相同,但经验表明,在应用和系统的整个生命周期内,维护两个相同的系统要比维护两个不同的系统更容易。无论如何,硬件架构必须相同 — 例如,从 32 位系统向 64 位系统传送日志是不可行的。
一般来说,不能在运行不同主版本 PostgreSQL 的服务器之间传送日志。PostgreSQL 全球开发组的策略是在次版本升级期间不改变磁盘格式,因此主库和备库运行不同次版本通常也能正常工作。不过,这方面并没有正式支持,因此仍建议主库和备库尽量保持在相同的发行级别。当升级到新的次版本时,最安全的策略是先升级备库 — 新的次版本更有可能兼容读取前一个次版本生成的 WAL 文件,反过来则未必。
启用备库服务器不需要任何特殊模式。主库和备库上执行的操作都是普通的持续归档和恢复任务。两台数据库服务器之间唯一的联系,就是它们共享的 WAL 文件归档:主库写入归档,备库从归档读取。必须确保不同主库的 WAL 归档不会混在一起或弄错。如果归档仅用于备库运行,则无需保留很大的归档。
使这两台松耦合的服务器协同工作的诀窍,只是备库上的一个restore_command:当被要求提供下一个 WAL 文件时,它会等待该文件从主库那边变为可用。restore_command在备库服务器的recovery.conf文件中指定。正常的恢复处理会向 WAL 归档请求文件,如果文件不可用则报告失败。而对于备库处理来说,下一个 WAL 文件不可用是正常情况,因此必须耐心等待它出现。等待型的restore_command可以写成一个自定义脚本,在轮询下一个 WAL 文件是否存在之后循环等待。还必须有某种触发故障切换的方法,它应中断restore_command、打破循环并向备库服务器返回一个 file-not-found 错误。这会结束恢复,备库随后将作为一台正常服务器启动。
一个合适的 restore_command 的伪代码如下:
triggered = false;
while (!NextWALFileReady() && !triggered)
{
sleep(100000L); /* wait for ~0.1 sec */
if (CheckForExternalTrigger())
triggered = true;
}
if (!triggered)
CopyWALFileForRecovery();
contrib中名为pg_standby的模块提供了一个可用的等待型restore_command示例。它应被用作如何正确实现上述逻辑的参考。也可以按需扩展它,以支持特定的配置和环境。
PostgreSQL并不提供用于识别主库故障并通知备库系统的系统软件。现在已经存在许多这样的工具,并且它们通常能很好地与成功故障切换所需的其他方面整合在一起,例如 IP 地址迁移。
触发故障切换的方法是规划和设计的重要部分。每个 WAL 文件都会执行一次 restore_command。运行 restore_command 的进程针对每个文件单独创建和结束,因此不存在守护进程或服务器进程,也无法使用信号或信号处理程序。所以,需要一种更持久的通知机制来触发故障切换。可以使用简单的超时机制,尤其是在已知主库 archive_timeout 设置的情况下配合使用。不过,这容易出错,因为网络问题或主库繁忙就可能导致故障切换。如果能够安排,显式创建触发文件之类的通知机制是理想的方式。
使用 restore_command 的 %r 选项可以使 WAL 归档最小化。此选项指定恢复正确重启所需要保留的最后一个归档文件名。如果归档对备库服务器可写,可以先用这一功能在文件不再需要时截断归档。
配置备库服务器的简要流程如下。各步骤的完整细节,参见所注明的前面章节。
尽可能将主库和备库系统配置得相同,包括安装两个完全相同、发行版本一致的 PostgreSQL 副本。
配置持续归档,将主库的 WAL 归档到备库上的一个目录。确保在主库上正确设置 archive_mode、archive_command 和 archive_timeout(参见 第 24.3.1 节)。
制作主库的基础备份(参见 第 24.3.2 节),并将这些数据装载到备库上。
在备库上从本地 WAL 归档开始恢复,在 recovery.conf 中指定前面所述的会等待的 restore_command(参见 第 24.3.3 节)。
恢复过程将 WAL 归档视为只读,因此,WAL 文件一旦复制到备库系统,就可以在备库读取它的同时,将其复制到磁带上。这样,既能运行备库提供高可用,又能保存文件用于更长期的灾难恢复。
为了测试,可以在同一个系统上同时运行主库和备库。这不会对服务器的稳健性带来有意义的提升,也不能称为高可用。
如果主库失效,备库就应该开始执行故障切换过程。
如果备库失效,则不需要发生故障切换。如果备库能够重新启动,即使是在稍后某个时间点,恢复过程也可以立即重新开始,从而利用可重启恢复的优势。如果备库无法重新启动,则应创建一个全新的备库实例。
如果主库失效之后又立即重启,你必须有一种机制通知它,它已经不再是主库。这有时被称为 STONITH(Shoot The Other Node In The Head),它对于避免两个系统都认为自己是主库的情况至关重要,因为那种情况会导致混乱,并最终造成数据丢失。
许多故障切换系统只使用两个系统,即主库和备库,并通过某种心跳机制连接它们,以持续验证两者之间的连通性以及主库的可用性。也可以使用第三个系统(称为见证服务器)来防止某些不恰当的故障切换,但除非设置得足够谨慎并经过严格测试,否则额外增加的复杂性可能并不值得。
一旦发生了向备库的故障转移,就只剩一台服务器在运行。这被称为退化状态。原备库现在是主库,但原主库已停机,而且可能一直停机。要恢复正常运行,必须重建一个备库——既可以在原主库系统重启后重建,也可以在第三台(可能是新的)系统上重建。完成后,可以说主库和备库交换了角色。有些人选择用第三台服务器为新主库提供备份,直到新的备库重建完成为止,尽管这显然会使系统配置复杂化并增加操作负担。
因此,从主库切换到备库可以很快,但重新准备故障切换集簇仍然需要时间。定期在主库与备库之间进行切换是有益的,因为它允许每个系统定期停机维护。这也相当于对故障切换机制进行测试,以确保真正需要它时它能够正常工作。建议编写书面的管理操作规程。
PostgreSQL直接支持前文所述的基于文件的日志传送。也可以实现基于记录的日志传送,但这需要自行开发。
外部程序可以调用 pg_xlogfile_name_offset() 函数(参见 第 9.23 节),取得当前 WAL 末尾所在的文件名及其在文件中的精确字节偏移。随后就可以直接访问 WAL 文件,将上次已知的 WAL 末尾到当前末尾之间的数据复制到备库。采用这种方法,可能丢失数据的时间窗口就是复制程序的轮询周期,可以很短,而且不会因为强制归档未写满的段文件而浪费带宽。注意,备库的 restore_command 脚本只能处理完整的 WAL 文件,因此这些增量复制的数据通常不会提供给备库使用。它们只有在主库失效时才有用 — 此时,在允许备库启动前,将最后一个不完整的 WAL 文件交给备库。要正确实现这一过程,restore_command 脚本必须与数据复制程序配合。
译文有误、术语不当或页面显示问题,请到译文仓库 pgsty/pgdoc 报告译文问题。 英文原文本身的问题,请在当前版本的对应页面向上游反馈;上游不再修订已结束维护的版本。