故障转移槽

来自 PostgreSQL 维基
跳转到导航跳转到搜索

故障转移槽(不成功的功能提案)

故障转移槽是 PostgreSQL 9.6 提出的一个功能该功能提案已被放弃。故障转移槽没有包含在 PostgreSQL 中,并且不太可能以该补丁中提出的形式包含在其中。但是,该功能背后的部分功能已经提交。

维基页面逻辑复制和物理备用故障转移讨论了上游和下游 PostgreSQL 实例的逻辑复制的物理故障转移支持的当前状态,以及可以使其成为可能的各种基于工具的策略。

部分提交

故障转移槽和备用上的逻辑解码补丁集背后的部分功能已经提交,包括

这足以允许外部工具通过将槽状态从主节点同步到备用节点来滚动自己的“故障转移槽”,尽管这样做正确起来有点微妙。有必要编写一个 C 扩展,它使用低级槽管理 API 创建复制槽,因为在编写本文时,没有 SQL 可见函数可以这样做。在原始故障转移槽补丁中可以找到这些 API 用法的示例 src/test/modules。

还有一些相关的补丁与故障转移和逻辑槽有关

相关的邮件列表讨论

使用工具实现复制槽故障转移

有了 PostgreSQL 10 中的上述补丁,现在可以实现在外部工具中对 PostgreSQL 逻辑复制槽进行故障转移管理。

备用必须配置为

  • hot_standby_feedback = on
  • 要在主节点上使用物理复制槽的 `primary_slot_name`

该工具将需要在每个故障转移候选备用节点上提供一个扩展,该扩展提供一种管理低级复制槽状态的方法,因为在编写本文时,PostgreSQL 中没有 SQL 接口用于此。这究竟是如何完成的,以及它是推模型还是拉模型等,都取决于该工具。在附在这封邮件上的补丁中,在 `src/test/modules/test_slot_timelines` 中可以找到一个非常简单且最小的示例。(工具不应该从主节点复制 `pg_replslot/*/state` 文件到备用节点;当服务器正在运行时,这些文件不会被备用节点重新读取,并且可能被来自共享内存的陈旧内容替换)。

为了管理故障转移,该工具应该定期扫描主节点的槽。对于该工具希望为备用节点的故障转移保留的每个逻辑复制槽,该工具应该在任何故障转移候选备用节点上创建/更新一个相同的逻辑复制槽。该工具必须检查备用节点是否已重放到槽的 `confirmed_flush_lsn`,并在必要时延迟同步该槽。同步槽时,备用节点槽的 `restart_lsn`、`confirmed_flush_lsn` 和 `catalog_xmin` 必须全部一起更新并持久化。该工具还应该在主节点上的槽不再存在时从备用节点中删除槽。

限制和注意事项

警告:请参见逻辑复制和物理备用故障转移,了解此方法周围的重大挑战。这不容易做对。

只有在备用节点的主节点上的物理槽的 `catalog_xmin` <= 槽的 `catalog_xmin` 之后,才可以在备用节点上提升后安全地使用任何给定的逻辑复制槽。在此之前,任何此类槽都是不安全的;它们可能有效,但会产生不完整或不正确的输出或使 walsender 崩溃。我建议您使用不同的名称(例如“_sync_temp1”或其他名称)创建它们,然后在已知 `catalog_xmin` 安全之后重命名它们(创建一个新的并删除临时槽)。您可以使用 `txid_status()` 函数来帮助您完成此操作,或者只观察主节点上的物理槽的 `catalog_xmin`。

即使使用这种方法,逻辑订阅者也可能在物理副本之前从主节点接收和应用事务。然后,故障转移可能会导致物理副本被提升,但没有此事务,因此提供者和订阅者现在存在差异。解决此问题需要对核心代码进行更改,以便向 walsender 教授如何延迟发送逻辑提交,直到它们被所有故障转移候选物理副本确认为止。欢迎为此提交补丁。单个输出插件可以在此期间通过在其提交回调中休眠,直到所有配置为副本的槽都已刷新到正在处理的提交的 lsn 之后,来解决此问题。输出插件必须提供自己的配置方法,以确定哪些槽/连接表示副本 - 将其重载到 `synchronous_standby_names` 中没有意义,并且您希望使用槽名称而不是备用连接名称。

主节点必须保留备用节点的物理复制槽。如果备用节点槽被删除并重新创建,则在再次同步它们之前,将无法安全地故障转移到备用节点并使用备用节点上的任何逻辑槽。工具无法简单地检测备用节点的主节点上的槽是否被删除并重新创建。

不幸的是,在复制槽管理代码中没有 C 级钩子函数供工具用于触发唤醒、同步或检查。需要轮询。

有关原始故障转移槽提案的信息

以下内容是保留的旧内容,以帮助理解主题的背景。

基本原理

我们需要故障转移槽来允许逻辑解码客户端跟踪物理故障转移,从而允许逻辑解码客户端“之上”的 HA。如果没有它,您无法可靠地从 HA Pg 安装流式传输数据到消息队列/ETL 系统/任何内容中,使用逻辑解码。您无法为逻辑复制部署、多主节点网状集群等中的节点创建物理 HA。您目前必须在故障转移后创建一个新槽,但您无法从故障转移前的当前状态过渡到与备用节点在创建槽时的重放位置一致的状态。

此补丁不会将所有槽都变成故障转移槽。由于故障转移槽必须在创建/前进/删除时写入 WAL,因此它们不能在恢复中的备用节点上使用。这意味着普通的非故障转移槽仍然有用 - 您可以使用物理槽从备用节点获取 WAL,并且应该可以添加对从备用节点进行逻辑解码的支持。

局限性

故障转移槽只能在主节点(原始节点或提升的备用节点)上创建、重放和删除。

以后的工作可以允许所有槽都成为故障转移槽,方法是引入一种槽记录机制,该机制“在”WAL 之外工作,允许备用节点拥有自己的故障转移槽,并将更改重放到其自己的级联备用节点上的那些槽中。这可以在不更改 UI 或破坏与第一个(9.6)版本一起工作的客户端的情况下完成,因为它们不会关心节点之间的传输是从 WAL 变成了……其他东西。要留待以后讨论,并且可能只能够使用槽和流式复制而不是归档恢复来工作。

我们现在需要故障转移槽,以使逻辑解码在生产环境中更有用。在级联备用节点上支持它们是“以后要做的”。

补丁说明

伴随补丁提交的额外说明。

逻辑解码后的时间线跟踪

这是使故障转移槽有用的必要条件。否则,从槽进行解码将在故障转移后失败,因为服务器尝试使用 ThisTimeLineID 读取 WAL,但所需的归档位于历史时间线上。虽然是补丁系列中最小的部分,但它是最复杂的。

我最初打算直接在 xlogreader 中添加对时间线跟踪的支持,但这与重做不兼容,入侵性更强,并且会导致使用 xlogreader 代码的前端代码(如 pg_xlogdump 和 pg_rewind)出现问题。因此,我将其实现为一个几乎独立的助手,逻辑解码回调可以调用它来要求 xlogreader 为它们跟踪时间线状态。它位于 xlogutils.c 中,而不是 xlogreader.c 中,因为它无法为前端代码编译。(后面的补丁可以使 timeline.c 为 FRONTEND 编译,将助手移至 xlogreader.c 并相对容易地在 pg_xlogdump 中添加对时间线跟踪的支持......如果有人关心。我认为没有必要。)

此补丁不使用 ReplicationSlotPersistentData 的 restart_tli 成员。该成员在当前的 94/95/96 代码中也是未使用的。我认为应该将其删除。我没有使用它,因为它没有帮助;仍然需要读取时间线历史文件以确定历史时间线的有效性边界,并且您也可能需要在其中查找给定历史点的的时间线。此外,尝试使用插槽的 restart_tli 与现有的使用 restart_lsn 来根据反馈懒惰地更新插槽的重启位置不一致。时间线跟踪必须在重播期间及时完成。在窥视的情况下,时间线切换也不会持久。尝试使用 restart_tli 来跟踪从哪个时间线读取新记录是错误且无用的。根本没有必要拥有它,因为我们可以使用时间线历史记录从重启 LSN 确定重启时间线。

可以通过创建一个在备用服务器上执行 ReplicationSlotCreate 的扩展,并使用旁路通道(应用程序等)来协调主服务器上的插槽镜像,从而单独使用补丁 1 中的时间线跟踪支持。

顺便说一句,我发现 Pg 中的时间线逻辑足够复杂,所以我打算跟踪一个 README 来描述它。我必须将所有这些都映射出来 - 以及 Pg 的不同部分处理时间线跟踪和 WAL 读取的不同方式 - 才能理解它。

故障转移槽

添加故障转移插槽,其状态更新记录在 WAL 中并在副本服务器上重播。

“在归档恢复启动时删除非故障转移插槽”这一观点需要更多解释。在 9.4 和 9.5 中,我们只是从 pg_basebackup 副本中省略 pg_replslot。因此,它们在备份中被有效地删除,仅针对备份副本。对于其他备份方法(如 rsync、磁盘快照等),它往往会被包含在内,并且服务器在从这种备份启动时会读取并保留这些插槽。这意味着在恢复时,我们可能会根据使用的方法保留插槽。如果保留了插槽,它们会将最小 LSN 保持在较低水平,并阻止副本上的 WAL 保留,因为副本会根据主服务器上的插槽副本的最新目录 xmin 独立决定 WAL 保留。此外,逻辑插槽会变得越来越*不正确*:它们的目录 xmin 不会前进,但主服务器上的真空(备用服务器正在从它重播)会根据主服务器上正在运行的插槽副本的最新目录 xmin 从目录中删除死行。没有任何东西会从基本备份中更新插槽的副本。

对于故障转移插槽,我更改了 pg_basebackup 以复制 pg_replslot,因为我必须复制故障转移插槽状态。另一种方法是确保备份检查点包含每个插槽,无论它是否被修改,但复制 pg_replslot 似乎更有意义,并且与正常恢复启动更加一致。但这使得现有过时插槽问题更加突出。

为了解决这个问题,作为此补丁的一部分,服务器现在在归档恢复启动期间删除非故障转移插槽 - 这包括真正的基于归档的恢复/PITR 和流式复制。


至于备份标签更改:我对这个不太强烈。它将允许备份工具确保复制和归档足够的 WAL 以保持故障转移插槽功能。它是无害的 - 所有常见工具都使用正则表达式从备份标签中提取内容,并且不会关心新行。它*不能*通过更改 START WAL LOCATION 来实现,因为服务器在开始归档恢复时使用它作为重做的起点,因此它必须是检查点的 REDO 指针。另一方面,pg_basebackup 从 BASE_BACKUP 命令的返回值获取有关最小 WAL 的信息,我将其更改为重做或故障转移插槽所需的 WAL 的最小值,因此它实际上不需要标签中的信息来正确执行其工作。在绝大多数情况下,如果您从备份中恢复,您将进行归档重播,因此任何故障转移插槽都会迅速超过在备份中保留的额外 WAL 的需求。但我宁愿 100% 解决这个问题,而不是让用户希望他们不会遇到这个窗口。尤其是由于插槽可能用于突发或延迟复制,这会扩大窗口。

请注意,插槽创建不会被重播到副本,直到插槽变得持久。这样,来自失败解码设置的临时插槽不会对副本有任何影响。不过,我希望对此部分给予额外的关注,因为我担心可能会存在这样的风险:由于这个原因,副本可能会在插槽变得持久并被复制之前删除插槽仍然需要的 WAL。如果您在此期间进行提升,您在副本上的插槽将被破坏。我无法复制它,并且我不相信它会发生,但可以接受审阅者的意见。我不直接复制临时插槽创建来解决此问题的原因是,临时插槽在崩溃恢复后在重做期间会静默删除,在这种情况下,我们无法写入 WAL 以告诉副本它不再需要保留其副本。


故障转移插槽的用户界面

添加 SQL 函数参数、walsender 关键字和视图更改以及文档更改。

没有向 pg_recvlogical 或 pg_receivexlog 的 --create-slot 选项添加 --failover 选项。您认为需要一个吗?