PostgreSQL 复制与高可用系列(四):逻辑复制深度实战——跨版本迁移、数据分发与冲突处理
Clyde Jin
04-24
DBA
47

PostgreSQL 复制与高可用系列(四):逻辑复制深度实战——跨版本迁移、数据分发与冲突处理

前三期我们完成了物理流复制从理论到实战的全链路学习,掌握了高可用架构的基石。 但物理复制有一个天然局限:它复制的是整个数据库集群,无法“选择性地同步几张表”,也不能在主备之间做异构同步(比如 12 → 17 跨大版本)。 第四期将聚焦逻辑复制——这张灵活的“手术刀”,为您打开数据同步的全新维度。

一、逻辑复制是什么?

1.1 定义与定位

逻辑复制是一种基于数据对象的复制标识(通常是主键)来复制数据对象及其更改的方法。这里使用“逻辑”一词来与物理复制(基于块地址和逐字节复制)加以区分——物理复制关注的是磁盘上数据块的变化,而逻辑复制关注的是数据的语义变化(插入、更新、删除)。

核心特点:PostgreSQL 同时支持物理复制和逻辑复制两种机制,两者可以并行运行,不互斥。这给了架构设计极大的灵活性。

1.2 架构:一次 WAL 的两面使用

逻辑复制的架构与物理流复制类似,同样由 walsenderapply 进程协作实现:

  1. 发布者walsender 进程启动对 WAL 的逻辑解码,加载标准输出插件 pgoutput。该插件将从 WAL 读取的变更转化为逻辑复制协议,并根据发布(Publication)规范进行筛选。
  2. 传输:数据通过流复制协议持续传输到订阅者的 apply 工作进程。
  3. 订阅者apply 进程将数据映射到本地表,并按照发布者上的提交顺序应用这些变更,确保事务一致性。

一个关键差异在于:逻辑复制 不会复制 DDL 命令——数据库模式和 DDL 命令不被复制。这一点下文会单独讨论。

至于订阅者的触发器行为,默认设置是会话复制角色为 replica,因此默认情况下触发器不触发;但用户可以通过 ALTER TABLE ... ENABLE TRIGGER 手动启用。

1.3 WAL 级别要求:一个关键决策点

逻辑复制要求 wal_level 设置为 logical。这个级别会写入比 replica 更多的 WAL 信息,以满足逻辑解码器的需求。请注意,设置为 logical 会增加 WAL 日志体积,可能对性能产生一定负面影响,因此在选择前需要审视具体的业务负载。如果只是临时启用逻辑复制(如一次性迁移),建议完成后恢复到 replica 以降低 WAL 开销。

二、发布与订阅模型

逻辑复制基于发布/订阅(Publication/Subscription)模型。概念定义如下:

  • 发布者:数据来源方,定义哪些表需要被复制(发布或 Publication)
  • 订阅者:数据目标方,定义连接信息和要订阅的发布(订阅或 Subscription)
  • 复制槽:发布者上持久化的标记,记录每个订阅者的消费进度,防止 WAL 被过早回收

2.1 创建发布(Publication)

-- 发布指定表的 INSERT 和 UPDATE(默认同步所有 DML)
CREATE PUBLICATION my_publication FOR TABLE users, orders;

-- 发布所有表(慎用,对系统表也会产生影响)
CREATE PUBLICATION all_tables FOR ALL TABLES;

-- 控制发布的 DML 类型:只复制 INSERT 和 UPDATE,不复制 DELETE
CREATE PUBLICATION insert_update_only 
FOR TABLE users 
WITH (publish = 'insert, update');

-- 仅发布部分列(最小化发送开销)
CREATE PUBLICATION limited_columns
FOR TABLE users (id, name, email);

publish 参数的可选值包括:insertupdatedeletetruncate,默认为全部四种。

2.2 创建订阅(Subscription)

-- 基础订阅:连接发布者并开始实时复制
CREATE SUBSCRIPTION my_subscription
CONNECTION 'host=192.168.1.10 port=5432 dbname=mydb user=replicator password=xxx'
PUBLICATION my_publication;

-- 仅复制新增数据,不拷贝已有数据(用于已有数据的场景)
CREATE SUBSCRIPTION delta_only
CONNECTION '...'
PUBLICATION my_publication
WITH (copy_data = false);

-- 禁用复制槽自动创建(专家场景,性能调优用)
CREATE SUBSCRIPTION manual_slot
CONNECTION '...'
PUBLICATION my_publication
WITH (create_slot = false, enabled = false);

一个订阅可以订阅来自同一个发布者的多个发布。当创建订阅时,如果 copy_data = true(默认),将在开始逻辑复制前,自动将发布者上的已有数据快照拷贝到订阅者。

2.3 查看与管理

-- 查看发布列表
SELECT * FROM pg_publication;

-- 查看发布的表
SELECT * FROM pg_publication_tables;

-- 查看订阅列表与状态
SELECT * FROM pg_subscription;

-- 查看复制槽状态
SELECT slot_name, plugin, slot_type, active, restart_lsn 
FROM pg_replication_slots;

三、快速搭建:跨版本迁移场景

假设要将一个 PostgreSQL 12 的 inventory 数据库迁移到 PostgreSQL 17(零停机在线迁移)。逻辑复制的典型用法是:升级数据库大版本、跨操作系统平台(如 Windows → Linux)复制、跨硬件架构(X86 → ARM)迁移等。

步骤 1:确保发布者有主键

逻辑复制依赖 REPLICA IDENTITY 来唯一标识行。如果表没有主键,UPDATEDELETE 操作无法正确同步到订阅者。

-- 检查哪些表没有主键
SELECT n.nspname AS schema, c.relname AS table
FROM pg_class c
JOIN pg_namespace n ON n.oid = c.relnamespace
WHERE c.relkind = 'r'
AND NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conrelid = c.oid AND contype = 'p')
AND n.nspname NOT IN ('pg_catalog', 'information_schema');

如果查询返回了表,请添加主键或设置 REPLICA IDENTITY FULL。后者有性能代价,但可作备选方案。

步骤 2:在 PostgreSQL 12(源库)启用逻辑解码

# postgresql.conf
wal_level = logical
max_replication_slots = 10          # 至少等于发布数量
max_wal_senders = 10                # 至少等于复制槽 + 备份等连接的预留

修改后需要重启。同时,pg_hba.conf 需允许目标库(新版本)的复制连接,并创建复制用户。

步骤 3:在 PostgreSQL 17(目标库)导入 Schema

由于 DDL 不会自动复制,需手动迁移表结构:

# 导出源库 schema(只导出结构,不导出数据)
pg_dump -h 192.168.1.10 -U postgres -d inventory --schema-only -f schema.sql

# 在目标库执行
psql -h 192.168.1.20 -U postgres -d inventory -f schema.sql

步骤 4:创建发布与订阅

-- 源库(12)上创建发布
CREATE PUBLICATION inv_pub FOR ALL TABLES;  -- 或指定表名列表

-- 目标库(17)上创建订阅
CREATE SUBSCRIPTION inv_sub
CONNECTION 'host=192.168.1.10 port=5432 dbname=inventory user=repuser'
PUBLICATION inv_pub
WITH (copy_data = true);

copy_data = true 会先执行一次全量数据拷贝,然后进入增量同步模式。数据量较大时,可考虑使用 PostgreSQL 17 的并行表同步能力(此功能已在 17 中上线,多个工作进程并行拷贝不同表,大幅缩短迁移窗口)。

步骤 5:验证切换

等待复制延迟追平后:

-- 在目标库上检查订阅状态
SELECT subname, subenabled, subslotname, suborigin FROM pg_subscription;

-- 在主库上查看复制进度
SELECT application_name, state, replay_lag 
FROM pg_stat_replication;

延迟追平后,停止对源库的写入,将应用流量指向目标库,源库降级。

四、DDL 不同步问题的深度解析

4.1 为什么 DDL 不会被复制?

这是逻辑复制当前最重要的限制之一。官方文档明确指出:“数据库模式和 DDL 命令不会被复制。”。

这意味着:在表上执行 ALTER TABLE ADD COLUMN 后,订阅者上需要手动执行同样的 DDL,否则复制会因表结构不匹配而报错。

4.2 设计哲学:为什么?

从架构设计来看,逻辑复制关注的是数据行级变化,而非表结构的语法命令。DDL 的复制会引入大量复杂性——不同 PostgreSQL 版本的 DDL 语法可能存在细微差异(如扩展语法、数据类型映射差异)。因此 PostgreSQL 团队的选择是:DDL 由管理员在两端手动维护。

4.3 手动保持 DDL 同步的最佳实践

  • 加法操作领先执行:在订阅者上先执行 ALTER TABLE ... ADD COLUMN,或者 CREATE INDEX,然后再在发布者上执行,避免数据类型不匹配的冲突。
  • 破坏性操作优先在发布者执行:删除列(DROP COLUMN)应在发布者上先执行,然后清理订阅者上对应的列。删除列前,确认订阅者是否还在依赖该列作为复用的判断条件。
  • 使用工具自动化:扩展 pgl_ddl_deploy(基于 pglogical 构建)能够自动将 DDL 语句传递给订阅者,但需要注意其版本兼容性。另一种方案是通过 pg_logical_emit_message 写入 DDL 消息到 WAL,由下游解析并执行。如果手写事件触发器捕获 DDL 并同步到订阅者,也是一种灵活但维护成本较高的方案。

4.4 生产环境示例:自动化 DDL 的代码级方案

-- 示例:创建一个事件触发器,将 DDL 以自定义消息形式写入 WAL
CREATE OR REPLACE FUNCTION capture_ddl()
RETURNS event_trigger AS $$
BEGIN
    PERFORM pg_logical_emit_message(false, 'ddl', current_query());
END;
$$ LANGUAGE plpgsql;

CREATE EVENT TRIGGER capture_ddl_trigger
ON ddl_command_end
EXECUTE FUNCTION capture_ddl();

下游可使用 pg_recvlogical 或应用程序消费 WAL 消息并执行 DDL。此种方式需要实现自己的执行逻辑,但能精确控制同步时机。

五、冲突处理(非常重要)

当订阅者上已经有本地修改,而发布者传来冲突的变更时,逻辑复制会停止并产生一个错误,需要手动解决

5.1 冲突的主要类型

冲突类型 场景描述 行为 处理方式
insert_exists 插入违反唯一约束的行 报错,停止复制 删除或更新冲突行后继续
update_missing UPDATE 找不到待更新行 自动跳过,不报错 无需处理(或做 INSERT 垫补)
update_exists 更新后违反唯一约束 报错,停止复制 手动修改约束违规的行
delete_missing DELETE 找不到待删除行 自动跳过,不报错 无需处理
multiple_unique_conflicts 同一行违反多个唯一约束 报错,停止复制 手动解决

官方明确指出:复制 UPDATEDELETE 操作时,缺少数据(即待更新的行不存在)不产生错误并且会被简单跳过。而违反唯一约束的冲突则会报错停止。

5.2 如何检测和解决冲突

订阅者的服务器日志会详细记录冲突信息。解决冲突的标准流程有两种:

  1. 修改订阅者端数据:删除或更新造成冲突的行,使其与传入的变更不冲突,然后恢复复制。
  2. 跳过冲突事务:使用 ALTER SUBSCRIPTION ... SKIP 跳过引起冲突的特定事务(支持从 PostgreSQL 16 开始)。注意,跳过事务可能导致数据不一致,请谨慎评估业务影响。

为了更深入的冲突检测(如 update_origin_differsdelete_origin_differs 类型),需要在订阅端启用 track_commit_timestamp 参数。

5.3 防止冲突的架构设计

在大多数高可用场景下,逻辑复制的最佳实践是:订阅者保持只读,不会发生双向写入。一旦订阅者参与写入(比如“多主”架构),冲突几乎不可避免。如果业务确实需要双向数据流动,建议考虑以下策略:

  • 数据分片:将不同主键范围映射到不同节点,确保同一个数据行始终只能由一个节点修改。
  • 延伸“最后一晚”模式:在冲突时倾向于保留最新的时间戳版本(可借助业务层或触发器实现)。

六、限制与注意事项

以下限制在实践中极易踩坑,务必提前知晓:

6.1 序列(Sequence)不会被复制

由序列支持的 serialidentity 列中的数据当然会作为表的一部分被复制,但序列本身在订阅者端仍显示起始值。如果计划进行故障切换让订阅者升级为新的主库,必须从发布者复制当前序列值或通过对表中已有数据取 MAX(id)+1 等方式更新序列值。这一问题在需要序列高度一致性(如分布式 ID 生成)的场景中需格外注意。

一个可行的处理方案:在故障切换后,对每个序列执行 SELECT setval('seq_name', (SELECT MAX(id) FROM table_name))

6.2 TRUNCATE 与外键的交互

复制 TRUNCATE 命令是支持的,但截断由外键连接的表组时需要格外小心。复制截断操作时,订阅者将截断发布者上被截断的同一组表(显式指定或通过 CASCADE 隐式收集的),不包括不属于该订阅的表。如果包含外键关系的表与不属于订阅的表存在外键链接,订阅者的截断将失败。

6.3 视图、物化视图、外部表不支持

逻辑复制只支持普通表和分区表。尝试复制视图、物化视图或外部表会报错。如需同步视图数据,一种常见方案是将视图查询结果物化到普通表后再复制。

6.4 大型对象(Large Objects)不会被复制

存储在 pg_largeobject 中的大型对象不会被复制,除了将数据存储在普通表格中外,没有其他解决方法。

6.5 REPLICA IDENTITY FULL 的潜在陷阱

在使用 REPLICA IDENTITY FULL 时,如果表中包含没有 B-tree 或 Hash 默认操作类的数据类型(如 pointbox),UPDATEDELETE 操作将无法应用于订阅者。遇到这种表时,建议设置主键或 REPLICA IDENTITY USING INDEX,避免 FULL 依赖带来的不确定性。

七、性能优化建议

逻辑复制相比物理复制有一定性能开销。以下针对不同场景的优化建议:

7.1 选择正确的出插件

  • pgoutput:PostgreSQL 内置的默认出插件。使用优化的二进制协议,无需额外安装即可使用。对于 PostgreSQL → PostgreSQL 的复制是性能最优的选择。实测在 1k TPS 场景下,端到端延迟通常在 20ms 以内。该插件通过 pgoutput 直接走 WAL 解析 + 流式发送,不经过 SQL 层,延迟较低。但如果是不需要跨版本复制或不需要 DDL 同步的简单拓扑,这也足够。
  • wal2json:将变更输出为 JSON 格式,便于异构系统集成,但性能开销较高。JSON 序列化在高频更新场景下 CPU 占用显著增加,实测单核 5k UPDATE/s 就可能吃满 CPU。优化建议:使用 add-tables 显式指定需要监听的表、设置 include-transaction = false 禁用事务头包装,以及启动 slot 时传入 include-previous = off 禁用旧值,可降低 20-40% CPU。
  • pglogical:在原生逻辑复制之前诞生的扩展,支持表级过滤、列裁剪、跨版本兼容(如 12 → 15)。延迟相对较高(80-150ms),因为多了一层逻辑解析和冲突处理。但它支持 DDL 同步(需显式启用),适合需要稳定同步 DDL 或需要行级冲突检测的场景。

7.2 逻辑复制槽管理

逻辑复制槽是维持 WAL 不被过早回收的关键机制。长期不活跃或被遗忘的槽将导致主库 WAL 堆积,最终磁盘写满。

最佳实践:

  • 设置 max_slot_wal_keep_size 参数,限制单个槽长期离线时保留的 WAL 总量。
  • 使用 pg_drop_replication_slot 删除不再使用的废弃槽。
  • 监控 pg_replication_slots 中的 activerestart_lsn 字段,设置告警。

7.3 批量设参优化

ALTER SYSTEM SET max_wal_senders = 20;
ALTER SYSTEM SET max_replication_slots = 20;

以上参数需要重启生效。此外,针对大数据量的复制集,可适当调大 work_memmaintenance_work_mem

7.4 增加并行优化

PostgreSQL 17 对逻辑复制做了重大改进:pg_upgrade 现可保留逻辑复制槽和订阅的完整状态,大版本升级后无需重新同步数据即可继续复制。如需在复制过程中搭建新节点,也可使用 pg_createsubscriber 工具,该工具可从物理备库创建逻辑副本。

八、PostgreSQL 17 新特性:值得关注的增强

自 PostgreSQL 17 起,逻辑复制获得多项重要更新:

  1. 故障槽(Failover Slots):允许逻辑复制在发生主库故障切换后继续工作,避免重新创建槽和重新同步的大开销。这是将逻辑复制纳入高可用体系的关键突破点。
  2. 升级保留pg_upgrade 现在保留发布者的逻辑复制槽和订阅者的完整订阅状态,使得大版本升级后逻辑复制能够快速继续,无需重新同步数据。这也意味着逻辑复制集群的平滑升级终于成为现实——但只适用于从 17.0 或更高版本升级的场景。
  3. 序列复制支持(PostgreSQL 18) :序列复制功能的支持已在 PostgreSQL 18 中引入,不同步序列的问题将逐步得到解决。

九、物理复制 vs 逻辑复制:场景总结

维度 物理流复制 逻辑复制
复制粒度 整个集群(实例级) 表级选择
复制内容 WAL 字节流(块级变化) 逻辑变更(行级 DML)
DDL 复制 ✅ 自动 ❌ 不支持(需手动同步)
跨大版本 ❌ 要求版本一致 ✅ 支持
选择性复制 ❌ 无 ✅ 有
冲突处理 不涉及(主备完全不写) 冲突可能发生,需要处理
主库写入性能影响 中等
典型用例 高可用主从、同城容灾 跨版本迁移、数据分发、业务解耦、CDC

一个常见组合:使用物理流复制维护高可用集群,在备库上再配置逻辑复制将特定表数据同步至数据仓库或分析系统。这是一种两全其美的架构。

十、一个完整的企业级逻辑复制架构

现代企业中的逻辑复制往往是多层次的:

  • 发布层:多个业务库分别定义自己的发布
  • 传输层:Kafka 或类似消息总线,通过 wal2json 等插件将 WAL 变更导入消息队列(CDC 范式)
  • 消费层:多个下游应用订阅各自的变更流(如实时数仓、搜索引擎、缓存刷新)

这种架构实现的优势:数据生产者与消费者的松耦合,下游数据产品可按需接入,上游数据库不受影响。

十一、写在最后

逻辑复制是 PostgreSQL 生态中最耀眼的功能之一。它从概念上把 WAL 从“只供数据库内部使用的物理日志”演变为“可被应用程序消费的变更流”——这一转变具有深远的架构意义:数据库系统不再是孤岛,而是可观测、可集成、可事件驱动的数据中枢。

本期系统梳理了:

  • 发布的创建与订阅管理
  • 跨版本零停机迁移的实操步骤
  • DDL 不同步的深层原因与自动化方案
  • 冲突类型、检测与解决策略
  • 出插件选型(pgoutput vs wal2json vs pglogical)
  • 性能优化与 PostgreSQL 17 新特性

第五期将深入 WAL 内核与 PITR 备份恢复,剖析 pg_basebackuppgBackRest 和 WAL 的完整生命周期管理。欢迎继续关注。

Star
Donate
PostgreSQL 复制与高可用系列(三):同步与异步复制工程实践——RPORTO 量化与性能权衡
Previous
PostgreSQL 复制与高可用系列(五):WAL 内核揭秘与 PITR 备份恢复——把时间掌握在自己手中
Next

Leave a comment

Registration is not required

Clyde Jin
303 Articles
0 Comments
0 Like
Recent Posts

HiddenMerit Daily · Issue 60

📊 HiddenMerit Daily · Issue 60 Focus on Database Frontiers, Practical Insights for DBAs July 22, 2026 | 5 Selected Global Breaking News 01|Oracle Releases Largest Quarterly Patch in History: 1,449 Patches Fix 1,235 CVEs, 261 Critical On July 21, Oracle released its July 2026 Critical Patch Update (CPU), setting a record for the largest single patch release in the company’s history. This CPU contains 1,449 security patches fixing 1,235 independent CVEs across 32 Oracle product families, of which 261 patches are rated Critical. Patch Distribution by Product Family: Product Family Patches Remotely Exploitable Without Authentication Oracle E‑Business Suite 410 45 Oracle Fusion Middleware 355 219 Oracle Communications 168 122 Oracle MySQL 54 9 Oracle Database Server 15 6 Context for This Patch: Oracle had already issued an urgent “Prepare Now” warning a week earlier, emphasising that AI is fundamentally lowering the barrier to discovering and exploiting vulnerabilities – frontier AI models can analyse software changes, reverse‑engineer security patches, and develop attack paths at unprecedented speed. Oracle has collaborated with state‑of‑the‑art models from Anthropic and OpenAI to proactively identify and fix potential security vulnerabilities. Oracle strongly recommends that customers immediately test and deploy this update in their monthly patch cycles. […]

HiddenMerit Daily · Issue 59

📊 HiddenMerit Daily · Issue 59 Focus on Database Frontiers, Practical Insights for DBAs July 21, 2026 | 5 Selected Global Breaking News 01|Oracle Issues Urgent Warning: July 21 Release Update to Fix Large Number of High‑Risk Vulnerabilities, Immediate Deployment Recommended On July 13, Oracle issued an urgent security warning, strongly recommending that all customers running supported Oracle Database versions (including Oracle Database 19c and Oracle AI Database 26ai) immediately test and deploy the Release Update (RU) after its release on July 21. Background: New frontier AI models are significantly lowering the barrier to discovering and exploiting software vulnerabilities – these models can identify weaknesses, analyse software changes, reverse‑engineer security patches, and develop potential attack paths at unprecedented speed and scale. AI models are also becoming increasingly adept at combining multiple weaknesses across the application and data stack into complex attacks, even when individual weaknesses do not themselves pose a serious risk. As a result, protecting systems solely at the network or application layer is no longer sufficient; enterprises must protect the entire technology stack. Fixes Included in This RU: Oracle has collaborated with state‑of‑the‑art models from Anthropic and OpenAI to proactively identify and fix potential security vulnerabilities. The upcoming […]

HiddenMerit Daily · Issue 58

📊 HiddenMerit Daily · Issue 58 Focus on Database Frontiers, Practical Insights for DBAs July 20, 2026 | 5 Selected Global Breaking News 01|CAICT: Domestic Databases Enter Core System “Deep Water,” AI‑Native Leads New Industry Landscape On July 9, at the 2026 Trustworthy Database Development Conference, CAICT released the “Database Development Research Report (2026).” The report notes that domestic databases have basically completed peripheral system replacement and have officially entered the critical business system breakthrough phase. Key Data: The global database market reached $131.6 billion in 2025 (approximately RMB 894.09 billion). The Chinese database market reached $9.49 billion in 2025 (approximately RMB 64.48 billion), and is expected to reach RMB 97.974 billion by 2028, with a CAGR of 13.06%. The number of domestic database vendors has shrunk from a peak of 167 to 94, with a clear head‑concentration effect and an intensifying “Matthew effect.” AI‑Native Becomes the Main Theme: The report points out that database technology is accelerating its evolution toward the AI‑native direction, and the global database industry is entering a new phase of landscape restructuring. The role of databases is upgrading from “underlying support systems” to “core engines enabling intelligent decision‑making and business innovation.” AI agents are becoming […]

HiddenMerit Daily · Issue 56

📊 HiddenMerit Daily · Issue 56 Focus on Database Frontiers, Practical Insights for DBAs July 6, 2026 | 5 Selected Global Breaking News 01|Kingware Releases Manufacturing Scenario Database Evolution White Paper: SQL Server Replacement Enters “Deep Water” On July 5, CETC Kingware published a technical article titled “Database Evolution in Manufacturing Scenarios: How Kingware Replaces SQL Server,” pointing out that the data surge on industrial shop floors has exceeded the processing capacity of single‑node systems. Traditional database architectures that rely on vertical scaling are facing unprecedented performance challenges. Over the next 1‑3 years, manufacturing enterprises will no longer face only the “choice of replacement,” but must answer the strategic question: “How do we build an autonomous data foundation in the context of de‑IOE?” Three Paradigm Shifts: Hybrid Workloads Become the Norm: The IT architecture of modern factories is shifting from separated OLTP and OLAP to HTAP mode. The same data system must simultaneously handle tens of thousands of device instruction writes per second and minute‑level production report analysis. Distributed Architecture Becomes a Hard Requirement: When a single table exceeds 100 million rows with daily increments exceeding 1 million rows, the index maintenance cost of traditional single‑node databases rises exponentially. Autonomous […]
生成中...
扫描二维码
扫描二维码