PostgreSQL 的逻辑复制常用于数据库迁移、读写分离和零停机升级。常规做法是先通过 pg_dump 在订阅端恢复一份基础数据,再创建订阅从某个复制槽位置开始同步增量。数据量大时,这份全量导出导入会占用大量时间和空间。pg_createsubscriber 的思路则不同,它允许把一台已经停止的物理流复制备库直接转换为逻辑订阅节点,因为备库本身已经有和主库一致的初始数据,自然不需要再执行一遍全量复制。

一、工具提供的核心能力:跳过全量初始化
物理复制和逻辑复制在 PostgreSQL 中是两套不同的机制。物理复制按 WAL 块原样传送,备库数据目录与主库逐字节一致;逻辑复制则是基于发布和订阅模型,只把指定表的行变更按逻辑协议发送。传统的逻辑订阅初始化没法直接复用物理备库的成果,因为逻辑订阅需要在订阅端创建 pg_subscription 元数据、关联复制槽,并让逻辑解码从正确位置开始工作。
pg_createsubscriber 在目标数据目录上完成这些转换工作。它假设 -D 参数指向的数据目录来自一台已停止的物理备库,并且该备库已经恢复到某个一致性点。工具会连接 -P 指定的旧主库,创建或使用复制槽,并在目标数据目录里写入逻辑订阅所需的系统表信息。这样,目标实例启动后就会被识别为一个逻辑订阅节点,后续变更会通过逻辑复制的复制槽持续同步。相当于把物理备库冻结的初始数据当成逻辑订阅的起点,省掉了最耗时的部分。
SELECT subname, subenabled FROM pg_subscription; SELECT slot_name, plugin, database FROM pg_replication_slots;
上面的查询可以在转换后的订阅实例上执行,确认订阅和复制槽是否建立成功。pg_createsubscriber 并不会立即启动目标服务器,它只负责改好数据目录,之后的启动和订阅状态检查需要 DBA 自己完成。
二、运行步骤与关键参数
使用前要满足几个条件。旧主库必须开启 wal_level=logical,同时 max_replication_slots 和 max_wal_senders 配置要能容纳新的逻辑复制槽。目标备库必须先停止,并且在停止前已经追平了旧主库,不能带着明显滞后运行 pg_createsubscriber。发布端还需要先创建好发布,比如针对 app 库中的业务表创建名为 app_pub 的发布。
典型命令如下:
pg_createsubscriber \ -D /var/lib/postgresql/17/main \ -P "host=old-primary dbname=app user=replication_user" \ -S "host=new-subscriber dbname=app user=postgres" \ --publication=app_pub \ --subscription=app_sub \ --replication-slot=app_sub_slot \ --dry-run
这里的 -D 是目标数据目录,也就是物理备库的数据目录。-P 连接旧主库,工具会从这里请求逻辑复制槽;-S 是订阅实例自己的连接串,它会在订阅元数据中记录为连接目标。--publication 和 --subscription 分别是旧主库上的发布名和将要创建在订阅端的订阅名。--replication-slot 指定槽名,不写时工具会使用订阅名作为槽名。建议第一次先带 --dry-run 跑一遍,确认连接串、权限和参数没有错误,再正式执行。
正式执行时去掉 --dry-run,命令会修改数据目录。完成后启动目标实例,再到旧主库确认复制槽正在被使用,同时可以在订阅端查询 pg_stat_subscription 观察 WAL 位点是否持续推进。需要注意的是,运行此命令时目标数据目录必须处于关闭状态,否则会因为文件锁或系统表一致性校验失败而报错。
三、常见限制和排障思路
pg_createsubscriber 并非银弹,它有几个明确限制。首先,它只适用于从物理流复制备库转换的场景,如果你没有一个已经同步好的物理备库,就没法用这个工具。其次,目标数据目录在转换前必须是一次干净的关闭,不能来自一个正在运行的实例的 live copy,否则系统表可能处于不一致状态。
另一个容易踩坑的地方是序列和 DDL。逻辑复制本身不自动同步序列状态,pg_createsubscriber 也不会额外处理序列值。如果应用依赖连续的主键序列,迁移后需要在订阅端手动调整序列当前值。同样,大对象和某些特殊类型可能不在发布表的范围中。建议迁移前梳理发布集合,确保所有需要复制的表都已加入发布。
SELECT subname, received_lsn, latest_end_lsn, last_error FROM pg_stat_subscription;
如果转换后订阅没有按预期工作,可以先看 pg_stat_subscription 里的 last_error 字段,常见错误包括旧主库复制槽丢失、pg_hba.conf 不允许订阅端连接、发布端 wal_level 没有设为 logical 等。这类错误通常不会由 pg_createsubscriber 在转换阶段报出,因为真正的逻辑复制开始于目标实例启动之后。转换成功后及时做一次日志检查和少量写入测试,能更早发现问题。
四、和传统初始化方式对比,什么样的场景适合它
与 pg_dump 加创建订阅的传统流程相比,pg_createsubscriber 的最大优势是省时间。一张几百 GB 的表如果走 pg_dump 导出再导入,可能需要几小时甚至更长,而 pg_createsubscriber 只需要在数据目录上写少量元数据,几分钟内就能完成。这个差异在停机窗口紧张时非常关键。
| 方式 | 初始化成本 | 适用情况 |
|---|---|---|
| pg_dump + 订阅 | 高,需全量导出导入 | 没有物理备库,或需要筛选转换数据 |
| pg_createsubscriber | 低,只写元数据 | 已有物理备库,初始数据可复用 |
不过它并没有完全替代传统方式。比如你只希望复制一部分表,或者目标库的数据模型和源库不同,这些场景仍然需要自己准备初始数据。pg_createsubscriber 最适合的是数据库整体迁移、主机替换、从旧的流复制拓扑切换到逻辑复制拓扑等操作。它把原本割裂的物理复制和逻辑复制连接起来,让 DBA 可以更灵活地规划复制架构。
总的来说,如果你手上已经有一台物理备库,又想把复制关系升级为逻辑订阅,pg_createsubscriber 是一个值得优先考虑的工具。它减少了一次全量数据拷贝,并且操作流程简单,命令参数也很直观。实际使用前做好 dry-run 和备份,基本能把风险控制在很低的范围。
PostgreSQLpg_createsubscriber逻辑复制修改时间:2026-10-03 14:16:00