触发器与逻辑订阅不能混用,因前者通过dblink执行外部SQL不生成WAL逻辑变更,后者依赖WAL解析事件且不传播触发器行为;二者“主动推”与“被动拉”机制冲突,易致数据丢失或死锁。

不能直接用触发器配合逻辑订阅实现跨云同步——这两者底层机制冲突,强行混用会导致数据丢失或死锁。
为什么触发器和逻辑订阅不能一起用于跨云同步
逻辑订阅(CREATE SUBSCRIPTION)依赖 WAL 日志中解析出的逻辑变更事件,它要求所有写入都通过标准 SQL 路径(INSERT/UPDATE/DELETE)进入事务流;而触发器函数内调用 dblink_exec 或写入外部表(postgres_fdw)属于「外部副作用」,不会生成可被逻辑复制捕获的 WAL 记录。
更关键的是:逻辑订阅本身不传播触发器行为,也不会重放触发器内部执行的远程 SQL。你在源库触发器里发往目标库的一条 INSERT,对逻辑订阅系统来说是完全不可见的。
- 触发器同步是「主动推」,靠源库主动连目标库执行语句
- 逻辑订阅是「被动拉」,靠目标库连接源库消费 WAL 解析后的变更
- 两者网络方向、权限模型、错误重试逻辑完全不同,无法共享状态或协同事务
跨云场景下该选逻辑订阅还是触发器
优先选逻辑订阅(CREATE PUBLICATION + CREATE SUBSCRIPTION),但必须满足几个硬性前提:
- 源库和目标库 PostgreSQL 版本兼容(建议同大版本,如 v13 ↔ v15 可行,v10 ↔ v16 风险高)
- 源库
wal_level = logical(修改后需重启) - 目标库能直连源库的内网地址(跨云需打通 VPC 对等连接或公网 TLS 加密通道)
- 待同步表必须有主键或定义
REPLICA IDENTITY,否则 UPDATE/DELETE 无法准确定位行
如果网络不可达(例如 AWS RDS 和阿里云 RDS 之间无专线)、或版本差异过大、或目标库不允许建 SUBSCRIPTION(部分托管服务限制),那就只能退回到触发器+dblink方案,但要接受它不是“跨云原生方案”,而是“人工模拟同步”的权宜之计。
真要混合用,只有一种安全组合方式
逻辑订阅负责主体 DML 同步(INSERT/UPDATE/DELETE),触发器仅用于补足逻辑订阅不支持的部分:DDL 同步、序列值传递、大对象(LOB)搬运、或跨库约束校验。
典型做法是:
- 在源库建一张
cc_pg_ddl_capture_tab表,用 DDL 触发器(event_trigger)把CREATE TABLE、ALTER COLUMN等操作写入该表 - 把这张表加入逻辑订阅的
PUBLICATION,让目标库收到 DDL 日志后自行解析执行 - 绝不允许触发器去改已被逻辑订阅管理的同一张表——否则会引发循环同步或主键冲突
这种分工下,触发器只是逻辑订阅的「辅助工具」,而非同步主力。一旦混淆角色,比如在逻辑订阅已启用的表上再加 AFTER INSERT 触发器去远程写,就等于在同一个数据流上叠加两套不协同的同步逻辑,出问题只是时间问题。
跨云同步最易被忽略的点,其实是网络稳定性与 WAL 保留时间的匹配。逻辑订阅断连超过源库 max_replication_slots 所能缓冲的 WAL 量,或者目标库延迟太久导致源库清理了旧 WAL,就会触发 replication slot advance failed 错误,且无法自动恢复——这比触发器连不上目标库更难诊断。

















