逻辑复制的行为在一点上类似于普通 DML 操作:即使订阅节点上的数据已在本地被修改, 传入的变更仍会更新它。如果传入数据违反了任何约束,复制就会停止,这种情况称为 冲突。在复制 UPDATE 或 DELETE 操作时,丢失的数据不会产生冲突,这类操作会被直接跳过。
逻辑复制操作会以订阅所有者角色的权限执行。目标表上的权限失败会导致复制冲突; 目标表上启用的、且订阅所有者受其约束的 行级安全 也会导致复制冲突,而不考虑任何 策略通常是否会拒绝当前复制的 INSERT、 UPDATE、DELETE 或 TRUNCATE。未来版本的 PostgreSQL 可能会取消这一行级安全限制。
冲突会产生错误并使复制停止;这类冲突必须由用户手工解决。有关冲突的详细信息 可以在订阅端的服务器日志中找到。
解决方法可以是修改订阅端上的数据或权限,使其不再与传入变更冲突;也可以跳过与 现有数据冲突的事务。当冲突导致错误时,复制不会继续,逻辑复制工作者会向订阅端 的服务器日志输出如下消息:
ERROR: duplicate key value violates unique constraint "test_pkey" DETAIL: Key (c)=(1) already exists. CONTEXT: processing remote data for replication origin "pg_16395" during "INSERT" for replication target relation "public.test" in transaction 725 finished at 0/14C0378
可以从服务器日志中找到包含违规变更的事务的 LSN 以及复制源名称 (在上述示例中分别是 LSN 0/14C0378 和复制源 pg_16395)。 可以使用 ALTER SUBSCRIPTION ... SKIP 并提供 finish LSN(即 LSN 0/14C0378)来跳过产生冲突的事务。这个 finish LSN 可以是该事务在发布端提交或准备完成时的 LSN。或者,也可以调用 pg_replication_origin_advance() 函数来跳过该事务。 在使用此函数之前,需要暂时禁用订阅,可以使用 ALTER SUBSCRIPTION ... DISABLE,或者让订阅使用 disable_on_error 选项。然后,可以使用 pg_replication_origin_advance() 函数, 传入 node_name(即 pg_16395) 以及 finish LSN 的下一个 LSN(即 0/14C0379)。当前各复制源的位置可以在 pg_replication_origin_status 系统视图中查看。 请注意,跳过整个事务也会跳过那些本来可能不违反任何约束的变更,这很容易导致 订阅端不一致。
当 streaming 模式为 parallel 时,失败事务的 finish LSN 可能不会被记录。 这种情况下,可能需要把 streaming 模式改为 on 或 off,并再次触发相同的冲突,以便将失败事务的 finish LSN 写入服务器日志。关于 finish LSN 的用法,请参见 ALTER SUBSCRIPTION ... SKIP。
如果您发现文档中有不正确的内容、与您使用特定功能的经验不符或需要进一步说明,请使用此表单来报告文档问题。