PostgreSQL逻辑复制是基于发布与订阅模型的数据同步方案,它允许把特定表或表中符合条件的行、列变更发送到远端实例。在实际生产中,我们往往不希望把整库所有数据都同步出去,比如只同步订单表中状态为已支付的记录,或者隐藏掉包含敏感信息的用户列。与此同时,逻辑复制链路本身不能成为系统的单点,一旦主库宕机或者网络分区,复制槽和订阅状态必须能够平稳接管,否则就会出现数据滞后甚至丢失。理解过滤策略与高可用机制,是设计跨机房同步和读写分离架构的基础。

发布端过滤策略的原理与写法
在PostgreSQL中,逻辑复制的过滤发生在发布(publication)定义阶段。我们可以通过CREATE PUBLICATION语句指定只发布某些表,并且从PostgreSQL 15开始支持行过滤(row filter)和列过滤(column filter)。行过滤依靠WHERE子句在发布端评估每一行变更,只有满足条件的行才会被编码到WAL并发送给订阅端;列过滤则通过FOR TABLE ... (col1, col2)语法限定只发布某些字段,减少传输体积。需要注意的是,行过滤表达式必须是确定性的,不能引用易变函数如now(),否则会导致发布端和订阅端数据不一致。
下面示例创建一个只同步orders表中status = 'paid'且只包含id、amount两列的发布。这种写法在账单同步场景中非常实用,既能降低带宽也能避免敏感字段外流。
-- 创建发布,只发布已支付订单的id与amount CREATE PUBLICATION orders_paid_pub FOR TABLE orders ( id, amount ) WHERE (status = 'paid'); -- 查看发布定义 SELECT pubname, schemaname, tablename, rowfilter FROM pg_publication_tables WHERE pubname = 'orders_paid_pub';
使用过滤策略时要留意几个限制。首先,若表上有主键值更新导致行不再满足过滤条件,默认旧行会在订阅端被删除,这种“消失”行为需要业务能接受。其次,列过滤下订阅端表结构可以少于发布端,但主键列必须包含在内,否则无法定位冲突。最后,过滤表达式不能包含子查询,复杂逻辑建议放在触发器或视图中预处理。
订阅端冲突处理与高可用基础
逻辑复制的订阅(subscription)在目标库以后台worker进程应用变更。当订阅端已存在相同主键数据,或由于过滤导致源端删除而目标端无记录时,就会抛出冲突错误。PostgreSQL提供conflict_resolution参数(部分版本通过apply_error_callback或手动处理)来控制策略,常见做法是配置skip或利用pg_replication_origin_advance跳过异常事务。对于高可用,关键点在于复制槽(replication slot)不能随主库故障而丢失,否则订阅端位点失效。
为保障高可用,推荐主库采用流复制备库,并开启sync_replication_slots(PG 16+)将逻辑槽同步到备库。当主库失效,备库提升后逻辑槽依然存在,订阅端只需重连新主即可继续消费。下面展示如何创建订阅并指定连接信息,以及如何在故障切换后重定向。
-- 在订阅端创建订阅 CREATE SUBSCRIPTION orders_sub CONNECTION 'host=192.168.0.1 port=5432 dbname=sales user=repl' PUBLICATION orders_paid_pub; -- 主库切换后,修改订阅连接(先断开) ALTER SUBSCRIPTION orders_sub DISABLE; ALTER SUBSCRIPTION orders_sub CONNECTION 'host=192.168.0.2 port=5432 dbname=sales user=repl'; ALTER SUBSCRIPTION orders_sub ENABLE;
除了槽同步,还应监控pg_stat_replication和pg_stat_subscription视图,确认延迟在阈值内。若使用Patroni或pg_auto_failover等工具,可把订阅连接串通过VIP或DNS自动漂移,减少人工干预。记住,逻辑复制不保证DDL同步,表结构变更需另行在两端执行,这也是高可用运维中容易被忽视的一环。
多节点架构下的过滤与切换实战
在跨机房多订阅场景中,不同机房可能只需要不同数据子集。此时可建立多个发布,比如机房A订阅全部订单,机房B只订阅欧洲区订单,通过行过滤WHERE (region = 'EU')实现。这种策略既能分摊负载,也降低了单个订阅端的存储压力。高可用上,每个订阅端都应配对独立槽,避免一个机房故障影响其他机房追数。
当源端发生版本升级或重大切换时,建议先在主库暂停应用写入,待所有订阅端pg_replication_origin_status的remote_lsn接近一致再操作。以下代码演示如何检查各订阅滞后情况,辅助切换决策。
-- 在订阅端查看接收与应用位点
SELECT subname,
received_lsn,
latest_end_lsn,
(received_lsn = latest_end_lsn) AS in_sync
FROM pg_stat_subscription;
-- 在发布端查看槽活跃状态
SELECT slot_name,
active,
restart_lsn,
confirmed_flush_lsn
FROM pg_replication_slots
WHERE slot_type = 'logical';
实战中还应考虑网络闪断后的自动重连,PostgreSQL订阅worker默认会重试,但频繁断开可能触发wal堆积。可调整wal_sender_timeout与wal_receiver_timeout适配弱网。通过合理设计过滤策略与槽同步机制,即使在主库滚动重启、备库提升的复杂环境下,逻辑复制也能维持高可用与数据可控,为业务提供连续同步能力。
PostgreSQL逻辑复制高可用修改时间:2026-08-15 16:56:31