逻辑解码是指将数据库表中所有持久性更改提取成一种连贯、易于理解的格式的过程,这种格式可以在不知道数据库内部状态的详细信息的情况下进行解释。
在 PostgreSQL 中,逻辑解码是通过解码 预写日志 (write-ahead log) 的内容来实现的,该日志描述了存储层面的更改,并将其解码成特定于应用程序的格式,例如元组流或 SQL 语句。
在逻辑复制的上下文中,复制槽代表了一个可以按照原始服务器上发生的顺序回放给客户端的更改流。每个复制槽都从单个数据库流式传输一系列更改。
PostgreSQL 还有流式复制槽(请参阅 第 26.2.5 节),但在此处它们的使用方式略有不同。
复制槽有一个在 PostgreSQL 集群的所有数据库中都唯一的标识符。复制槽独立于使用它们的连接而存在,并且是崩溃安全的。
在正常操作中,逻辑复制槽只会发出每个更改一次。每个复制槽的当前位置仅在检查点时持久化,因此在发生崩溃的情况下,复制槽可能会回退到较早的 LSN,这将在服务器重新启动时导致最近的更改被再次发送。逻辑解码客户端负责避免处理同一消息多次而产生的负面影响。客户端可能希望记录它们在解码时看到的最后一个 LSN,并跳过任何重复的数据,或者(在使用复制协议时)请求从该 LSN 开始解码,而不是让服务器确定起始点。复制进度跟踪功能就是为此目的而设计的,请参阅 复制源。
对于单个数据库,可以存在多个独立的复制槽。每个复制槽都有自己的状态,允许不同的使用者从数据库更改流中的不同点接收更改。对于大多数应用程序,每个使用者都需要一个单独的复制槽。
逻辑复制槽不了解接收者(或接收者们)的状态。甚至可能在不同时间有多个不同的接收者使用同一个复制槽;它们只会获取上一个接收者停止消耗它们之后的更改。在任何给定时间,只有一个接收者可以从一个复制槽消耗更改。
逻辑复制槽也可以在热备服务器上创建。为防止 VACUUM
从系统目录中移除必需的行,应在备服务器上设置 hot_standby_feedback
。尽管如此,如果任何必需的行被移除,复制槽就会失效。强烈建议在主服务器和备服务器之间使用物理复制槽。否则,hot_standby_feedback
将仅在连接存活时起作用(例如,节点重启会破坏它)。然后,主服务器可能会删除备服务器上的逻辑解码可能需要的系统目录行(因为它不知道备服务器上的 catalog_xmin
)。如果在主服务器上将 wal_level
降低到低于 logical
,备服务器上现有的逻辑复制槽也会失效。一旦备服务器检测到 WAL 流中的这种变化,就会发生这种情况。这意味着,对于延迟的 walsender(如果有的话),主服务器上 wal_level
参数更改之前的某些 WAL 记录将不会被解码。
创建逻辑复制槽需要有关所有当前正在运行事务的信息。在主服务器上,此信息可直接获得,但在备服务器上,必须从主服务器获取此信息。因此,复制槽的创建可能需要等待主服务器上发生某些活动。如果主服务器处于空闲状态,在备服务器上创建逻辑复制槽可能需要显著的时间。这可以通过在主服务器上调用 pg_log_standby_snapshot
函数来加速。
复制槽在崩溃后仍然存在,并且不了解其消费者(或消费者们)的状态。即使没有连接使用它们,它们也会阻止移除必需的资源。这会消耗存储空间,因为只要复制槽需要,VACUUM
就无法移除必需的 WAL 或系统目录中的必需行。在极端情况下,这可能导致数据库关闭以防止事务 ID 回绕(请参阅 第 24.1.5 节)。因此,如果不再需要复制槽,就应该将其删除。
主服务器上的逻辑复制槽可以通过使用 pg_create_logical_replication_slot
的 failover
参数,或通过在复制槽创建期间使用 CREATE SUBSCRIPTION
的 failover
选项来同步到热备服务器。此外,还需要在备服务器上启用 sync_replication_slots
。通过在备服务器上启用 sync_replication_slots
,可以在 slotsync 工作进程中定期同步故障转移复制槽。为了使同步正常工作,必须在主服务器和备服务器之间有一个物理复制槽(即,在备服务器上配置了 primary_slot_name
),并且在备服务器上必须启用了 hot_standby_feedback
。还必须在 primary_conninfo
中指定一个有效的 dbname
。强烈建议在主服务器的 synchronized_standby_slots
列表中命名上述物理复制槽,以防止订阅者比热备服务器更快地消耗更改。即使配置正确,由于等待 synchronized_standby_slots
中命名的复制槽,在将更改发送给逻辑订阅者时也可能存在一些延迟。当使用 synchronized_standby_slots
时,主服务器不会完全关闭,直到与 synchronized_standby_slots
中指定的物理复制槽关联的备服务器确认接收了 WAL 到主服务器上的最新刷新位置。
虽然启用 sync_replication_slots
允许自动定期同步故障转移复制槽,但也可以在备服务器上使用 pg_sync_replication_slots
函数手动同步它们。然而,此函数主要用于测试和调试,应谨慎使用。与自动同步不同,它不包含循环重试,使其更容易发生同步失败,特别是在初始同步场景中,此时所需的 WAL 文件或复制槽的目录行可能已被移除或有被移除的风险。相比之下,通过 sync_replication_slots
进行的自动同步提供连续的复制槽更新,从而实现无缝故障转移并支持高可用性。因此,它是同步复制槽的推荐方法。
当复制槽同步按照建议进行配置,并且初始同步由 pg_sync_replication_slots
自动或手动完成时,备服务器仅在满足以下条件时才能持久化同步的复制槽:主服务器上的逻辑复制槽必须保留备服务器上仍可用的 WAL 和系统目录行。这确保了数据完整性,并允许在提升后逻辑复制顺利继续。如果所需的 WAL 或目录行已从备服务器中清除,复制槽将不会被持久化以避免数据丢失。在这种情况下,可能会出现以下日志消息
LOG: could not synchronize replication slot "failover_slot" DETAIL: Synchronization could lead to data loss, because the remote slot needs WAL at LSN 0/3003F28 and catalog xmin 754, but the standby has LSN 0/3003F28 and catalog xmin 756.
如果逻辑复制槽被消费者主动使用,则无需手动干预;复制槽将自动前进,并在下一个周期恢复同步。但是,如果没有配置消费者,建议使用 pg_logical_slot_get_changes
或 pg_logical_slot_get_binary_changes
在主服务器上手动推进复制槽,从而允许同步继续。
在故障转移后恢复逻辑复制的能力取决于故障转移时备服务器上同步复制槽的 pg_replication_slots.synced
值。只有在故障转移前在备服务器上达到同步状态为 true 的持久化复制槽才能在故障转移后用于逻辑复制。临时同步的复制槽不能用于逻辑解码,因此这些复制槽的逻辑复制无法恢复。例如,如果同步的复制槽由于禁用了订阅而无法在备服务器上持久化,那么即使重新启用订阅,在故障转移后也无法恢复订阅。
要从同步的逻辑复制槽恢复逻辑复制,必须更改订阅的 'conninfo' 以指向新的主服务器。这可以通过 ALTER SUBSCRIPTION ... CONNECTION
来完成。建议在提升备服务器之前先禁用订阅,并在更改连接字符串后重新启用它们。
有可能在提升期间旧的主服务器会重新上线,并且如果订阅没有被禁用,逻辑订阅者可能会继续从旧的主服务器接收数据,即使在提升之后,直到连接字符串被更改。这可能会导致数据不一致问题,从而阻止逻辑订阅者能够从新的主服务器继续复制。
输出插件将预写日志的内部表示形式中的数据转换为复制槽使用者所需的格式。
当使用流式复制接口(请参阅 CREATE_REPLICATION_SLOT)创建新的复制槽时,会导出一个快照(请参阅 第 9.28.5 节),该快照将准确显示数据库在所有更改将被包含在更改流中的状态。这可以用于创建新的副本,方法是使用 SET TRANSACTION SNAPSHOT
读取复制槽创建时的数据库状态。然后可以使用此事务转储当时数据库的状态,之后可以使用复制槽的内容进行更新,而不会丢失任何更改。
不需要快照导出的应用程序可以使用 SNAPSHOT 'nothing'
选项将其禁用。
如果您在文档中发现任何不正确之处,与您对特定功能的体验不符,或需要进一步澄清,请使用 此表单 报告文档问题。