PostgreSQL 17 引入了逻辑复制槽故障转移功能,该功能的核心价值在于:当主库发生故障且备库被提升为新主库时,无需重新创建逻辑复制槽即可安全、不丢失数据地接管原有的逻辑复制流,从而极大提升了基于逻辑复制的数据库高可用架构的可靠性。
关键配置参数
实现复制槽同步功能涉及以下三个关键配置参数:
| 参数名 |
生效位置 |
说明 |
hot_standby_feedback |
备库 |
必须开启,用于通知主库保留备库可能需要的旧数据版本。 |
sync_replication_slots |
备库 |
控制是否启动后台进程自动同步复制槽信息。 |
synchronized_standby_slots |
主库 |
指定一组物理复制槽名,确保数据先同步到物理备库,再发送给逻辑下游,保障故障切换后的数据一致性。 |
功能演示:手动同步逻辑复制槽
下面通过一个完整示例演示逻辑复制槽同步的手动操作流程。
环境准备
- 主库A: 设置
wal_level=logical。
- 备库B: 设置
hot_standby_feedback=on,并通过 primary_slot_name='standby1' 连接主库。
- 逻辑下游C: 用于订阅逻辑复制数据。
步骤一:在主库创建逻辑复制槽
在主库A执行以下命令,注意最后一个参数需设置为 true,这表示该槽需要被同步到备库。
postgres=# select pg_create_logical_replication_slot('pub_slotname1', 'pgoutput', false, false, true);
pg_create_logical_replication_slot
-------------------------------------------
(pub_slotname1,0/5000098)
(1 row)
步骤二:在备库手动触发同步
首先,在备库B查看当前复制槽状态(此时应为空):
postgres=# select * from pg_replication_slots;
slot_name | plugin | slot_type | datoid | database | temporary | active | active_pid | xmin | catalog_xmin | restart_lsn | confirmed_flush_lsn | wal_status | safe_wal_size | two_phase | two_phase_at | inactive_since | conflicting | invalidation_reason | failover | synced
-----------+--------+-----------+--------+----------+-----------+--------+------------+------+--------------+-------------+---------------------+------------+---------------+-----------+--------------+----------------+-------------+---------------------+----------+--------
(0 rows)
然后,执行手动同步命令:
postgres=# select pg_sync_replication_slots();
pg_sync_replication_slots
---------------------------
(1 row)
再次查看,确认主库的 pub_slotname1 槽已同步到备库:
postgres=# select slot_name,restart_lsn,confirmed_flush_lsn from pg_replication_slots;
slot_name | restart_lsn | confirmed_flush_lsn
---------------+-------------+---------------------
pub_slotname1 | 0/5000060 | 0/5000098
(1 row)
步骤三:配置逻辑发布与订阅
在主库A创建发布:
CREATE PUBLICATION all_tables_pub FOR ALL TABLES;
在逻辑下游C创建订阅,并指定使用已存在的复制槽 pub_slotname1:
postgres=# CREATE SUBSCRIPTION sub_to_main
CONNECTION 'host=localhost port=10080 dbname=postgres user=lchch password=secret'
PUBLICATION all_tables_pub
WITH (slot_name = 'pub_slotname1', create_slot = false);
CREATE SUBSCRIPTION
步骤四:验证数据同步与槽位点更新
在主库A插入测试数据,并观察复制槽位点推进:
postgres=# insert into t1 values(100,1,'aa');
INSERT 0 1
postgres=# select slot_name,restart_lsn,confirmed_flush_lsn,active from pg_replication_slots ;
slot_name | restart_lsn | confirmed_flush_lsn | active
---------------+-------------+---------------------+--------
pub_slotname1 | 0/5000D58 | 0/5000D90 | t
standby1 | 0/5000D90 | | t
(2 rows)
此时,备库B上的同步槽位点尚未更新:
postgres=# select slot_name,restart_lsn,confirmed_flush_lsn,active from pg_replication_slots ;
slot_name | restart_lsn | confirmed_flush_lsn | active
---------------+-------------+---------------------+--------
pub_slotname1 | 0/5000060 | 0/5000098 | f
(1 row)
在备库B再次执行手动同步,可见槽的 confirmed_flush_lsn 已更新至与主库一致:
postgres=# select pg_sync_replication_slots();
pg_sync_replication_slots
---------------------------
(1 row)
postgres=# select slot_name,restart_lsn,confirmed_flush_lsn,active from pg_replication_slots ;
slot_name | restart_lsn | confirmed_flush_lsn | active
---------------+-------------+---------------------+--------
pub_slotname1 | 0/5000BD0 | 0/5000D90 | f
(1 row)
至此,演示完成。此时若主库A宕机,VIP漂移至备库B并使B库升主,逻辑下游C即可无缝、无数据丢失地继续从新主库进行逻辑复制,实现了平滑的主备切换。
内核逻辑深度解读
上述演示使用了手动同步命令,若开启 sync_replication_slots 参数,Postmaster会启动一个后台进程,循环检查并自动同步复制槽。该进程的等待时间会根据复制活动动态调整(从200ms到30s),以平衡及时性和系统开销。
实现此功能的核心机制与限制如下:
-
依赖 hot_standby_feedback: 备库必须开启此参数。其主要目的是保护备库上可能已被逻辑解码事务引用的catalog(系统表)数据不被过早清理。这样,故障转移后,新主库仍有完整的元数据支持逻辑解码。但这可能加剧主库因无法及时清理死元组而产生的表膨胀问题。
-
同步的发起与内容: 同步操作由备库主动发起。备库连接主库,查询主库上所有标记为可同步的复制槽信息,并据此在本地创建或更新对应的“同步复制槽”。同步的不仅是LSN位点,更关键的是维护解码所需的一致性快照信息。因此,在开启此功能后,备库至少需要额外读取一次WAL日志来维护快照,这对备库性能有一定影响。
-
处理WAL缺口问题: 在备库创建同步槽时,若该槽所需的最早WAL日志已在备库被删除,则会创建一个“非法”的槽,并为其设置一个非常大的LSN(InvalidXLogRecPtr)。在后续同步更新槽位点时,也可能因维护快照失败而将槽位点设置为一个超大值。这会导致备库同步槽的LSN反而大于主库原槽的LSN。
-
同步等待机制: 针对上述“备库槽位点超前”的特殊情况,最新的内核补丁增加了等待逻辑。当手动执行 pg_sync_replication_slots() 遇到此情况时,函数会阻塞,直到主库上对应逻辑复制槽的消费位点(confirmed_flush_lsn)追平或超过备库上同步槽的超前位点后,才返回成功。这确保了同步操作的最终正确性。
总结与展望
PostgreSQL 17的逻辑复制槽同步功能,为解决逻辑复制下的高可用问题迈出了关键一步。其设计在追求正确性的过程中,不可避免地引入了对主库膨胀的潜在影响(hot_standby_feedback)以及备库额外的性能开销(多次读取WAL)。这反映了在构建健壮的数据库高可用方案时,往往需要在特性、性能与复杂度之间进行权衡。当前实现已解决了核心的数据一致性问题,相信未来版本会在此基础上持续优化,寻求更优的平衡点。
