PostgreSQL 18 中文参考文档(未翻译部分保留英文)🌐 切换到英文原版 →

47.2. 逻辑解码概念与架构 #

47.2.1. 逻辑解码核心原理
47.2.2. 复制槽
47.2.3. 复制槽同步
47.2.4. 输出插件
47.2.5. 导出快照

47.2.1. 逻辑解码核心原理 #

逻辑解码是指将对数据库表中执行的所有持久化变更提取为连贯、易于理解的格式的过程,该格式在脱离数据库底层内部物理状态细节的前提下依然能够被直接解释消费。

在 PostgreSQL 内部,逻辑解码通过解析预写式日志(WAL)实现:将物理存储层面的二进制变更还原为应用程序特定的表现形式,例如元组流或 SQL 语句。

47.2.2. 复制槽 #

在逻辑复制体系中,复制槽代表了一条有序的数据变更流,能够按照源端服务器上事务提交的原始物理顺序精准回放给客户端。每个复制槽专门流式传输单一数据库内部的数据变更。

Note

PostgreSQL 同样拥有物理流复制槽(参见 Section 26.2.5),但在工作机制与应用方式上存在若干差异。

复制槽拥有在单个 PostgreSQL 集群所有数据库间全局唯一的标识符。复制槽独立于使用它的物理连接而持久存在,具备完全的物理崩溃安全性。

在常规正常运行状态下,逻辑复制槽对每条数据变更仅发送一次。由于每个复制槽的当前位点仅在发生检查点(Checkpoint)时才会持久化固化到磁盘,若遇到突发断电崩溃,重启后复制槽可能会退回到较早的 LSN 位点,从而导致近期已发送过的变更再次重发。逻辑解码客户端必须负责防范重复消息带来的负面影响。客户端应在消费时记录所见到的最新 LSN,跳过任何重复数据,或(在通过流复制协议连接时)请求服务端严格从该 LSN 处起步解码。复制进度跟踪(Replication Progress Tracking)基础设施正是为此而设计,详情参见复制源。

单个数据库内可以并行创建多个完全独立的复制槽。每个复制槽维护专属的状态位点,允许不同的外部消费者从数据变更流中完全不同的时间起点拉取数据。对于大多数业务系统,应为每个独立的消费者分配专用的复制槽。

逻辑复制槽对接收端的状态一无所知。甚至可以在不同时间由不同的接收端接入同一个复制槽;后续接入的接收端将紧接着上一个接收端停止消费的位点继续读取。在任意时刻,每个复制槽仅允许单一接收端建立连接消费。

逻辑复制槽同样可以在备库(Hot Standby)上创建。为了防止备库上的 VACUUM 提前清理逻辑解码所需的系统目录行,必须在备库上开启 hot_standby_feedback。尽管如此,若任何所需数据行遭清理,该复制槽将被标记失效。强烈建议在主库与备库之间使用物理复制槽。此外,一旦主库上的 wal_level 降至 logical 以下,备库上的逻辑槽也会被立即置为失效。

创建逻辑复制槽需要获取当前正在运行的所有活跃事务的信息。在主库上此信息立即可用,但在备库上必须从主库同步获取。因此,在空闲备库上建槽可能需要等待主库产生写入活动;在主库上调用 pg_log_standby_snapshot 函数可以大幅加速备库建槽。

Caution

复制槽在系统崩溃后持久存在,且对其消费者的健康状态毫不知情。即使没有任何客户端连接,只要复制槽存在,它就会阻止系统回收所需的 WAL 日志以及系统目录中的旧行,因为 VACUUM 不能清理复制槽仍需的物理资源。在极端情况下,这可能导致磁盘被 WAL 撑爆或因事务 ID 环回风险而导致数据库停机保护(参见 Section 24.1.5)。因此,一旦某个复制槽不再需要,请务必将其显式删除。

47.2.3. 复制槽同步 #

主库上的逻辑复制槽可以通过在调用 pg_create_logical_replication_slot 时指定 failover 参数,或者在执行 CREATE SUBSCRIPTION 时使用 failover 选项,自动同步到备库。此外,必须在备库上开启 sync_replication_slots。开启该参数后,备库的 slotsync 工作进程会周期性同步故障转移槽。为此,主库与备库之间必须配置物理流复制槽(即在备库配置 primary_slot_name),且备库必须开启 hot_standby_feedback,并在 primary_conninfo 中指定合法的 dbname。强烈建议在主库的 synchronized_standby_slots 中登记该物理槽名称,以防止下游订阅者消费进度快于备库。

Note

虽然开启 sync_replication_slots 能够实现周期的自动同步,但在备库上也可以通过调用 pg_sync_replication_slots 手动触发单次同步。但该函数主要用于测试与调试,不具备自动重试机制,推荐以自动同步作为生产高可用首选。

当按照规范配置槽同步后,仅当主库逻辑复制槽所保留的 WAL 及系统目录行在备库上依然完整可用时,备库才能成功持久化该同步槽,以防数据丢失。

在主备故障切换(Failover)后,下游逻辑订阅能否无缝恢复取决于故障发生瞬间备库上该同步槽的 synced 状态。只有在切换前已在备库持久固化且处于 true 状态的同步槽,才被允许在故障转移后用于逻辑复制续传。

在完成主从倒换后,必须通过 ALTER SUBSCRIPTION ... CONNECTION 将下游订阅者的连接串指向晋升后的全新主库。建议在晋升前先在订阅端停用(Disable)订阅,待修改连接信息完成后再重新启用。

Caution

在备库晋升期间旧主库可能再次恢复运行,若未提前停用订阅,订阅端可能继续从旧主库拉取数据,引发严重的数据不一致冲突。

47.2.4. 输出插件 #

输出插件的作用是将 WAL 日志中的内部二进制存储格式转换为复制槽消费者所期望的目标呈现格式。

47.2.5. 导出快照 #

当使用流复制协议接口新建复制槽时(参见 CREATE_REPLICATION_SLOT),系统会导出一个物理快照(参见 Section 9.28.5)。该快照精确反映了复制槽创建时刻数据库的状态,此后产生的所有变更都会按序进入该槽的变更流中。外部工具可以配合 SET TRANSACTION SNAPSHOT 读取该精准时刻的数据状态并全量导出初始基线数据,随后衔接复制槽中流出的增量变更,实现零丢失平滑同步。对于无需导出快照的客户端,可以通过 SNAPSHOT 'nothing' 显式禁用快照导出。