postgresql的逻辑复制-订阅和发

postgresql的逻辑复制-订阅和发

下面给出一份“从 0 到 1”能跑通的 PostgreSQL 逻辑复制(发布-订阅) 速查手册,涵盖原理、限制、配置步骤与完整案例,全部命令均基于 PG 16 验证通过,复制即可用。

一、逻辑复制是什么

1.发布-订阅模型:

  • 发布者(publisher)→ 创建 Publication(表级变更集合)
  • 订阅者(subscriber)→ 创建 Subscription(连接+订阅集合)
    2.与物理流复制的区别
  • 只复制 部分表/部分操作;订阅端 可写;支持 跨大版本/跨平台
  • 不支持 DDL、Sequence、大对象
    3.后台进程
  • 订阅端:logical replication launcher → apply worker → tablesync worker(每张初始表一个)

二、快速 checklist(先确认再动手)

发布端 订阅端
版本 ≥ 10 ≥ 10
wal_level logical
max_replication_slots ≥ 1
max_logical_replication_workers ≥ (表数+1)
表结构 有 PK 或 UK 与发布端一致
网络 pg_hba.conf 允许 replication 连接 能连通发布端

逻辑复制的发布端的安全和权限控制如下:

  • 1.必须设置pg_hba.conf,允许订阅端通过流复制连接发布端。
  • 2.wal_level必须设置为“logical”,以记录逻辑复制的一些额外信息。
  • 3.订阅端配置的conninfo中,发布端的角色必须具备权限或者超级用户权限。
  • 4.使用某个用户在某个数据库中创建publication,此用户必须对该数据库具备CREATE权限。

逻辑复制的订阅端的安全和权限控制如下:

  • 1.订阅端创建subscription的用户必须是超级用户。
  • 2.权限检测仅在连接发布端的时候进行,后期不会检测,比如从发布端获取数据或者apply数据时,不再检测是否为超级用户

与逻辑复制相关的参数有以下几个

·wal_level:必须设置为“logical”,让WAL日志文件中记录逻辑解码所需的信息,低于这个级别,逻辑复制不能工作。
·max_wal_senders(integer):指定来自备用服务器或流式基本备份客户端的最大并发连接数(同时运行的WAL发送器进程的最大数)。默认值为“10”,“0”表示复制被禁止。应将此参数设置为略高于预期客户端的最大数量。该参数只能在服务器启动时设置。
·max_replication_slots(integer):指定服务器可以支持的最大复制插槽数。默认值为“10”。只能在服务器启动时设置此参数。将其设置为小于当前现有复制插槽数的值将导致服务器无法启动。
·wal_sender_timeout(integer):不活动的复制连接的时间超过这个参数指定的毫秒数,就会被终止掉。这对于发送服务器检测备用崩溃或网络中断很有用。0值将禁用超时机制。默认值为60秒。
·track_commit_timestamp(boolean):记录事务的提交时间。默认值为“off”。

三、最小可运行案例(单表增量同步)

环境假设
发布端:192.168.1.10:5432 用户:repl / pwd123
订阅端:192.168.1.20:5432 用户:postgres

步骤 1 发布端配置

-- postgresql.conf
listen_addresses = '*'
wal_level = logical
max_replication_slots = 10

-- pg_hba.conf  新增
host  all  repl  192.168.1.20/32  md5
host  replication repl 192.168.1.20/32 md5

-- 重启
pg_ctl restart

-- 建库、建表、建发布
CREATE DATABASE demo;
\c demo
CREATE TABLE public.t1(id int PRIMARY KEY, info text, ts timestamp DEFAULT now());

CREATE PUBLICATION pub1 FOR TABLE public.t1;
-- 如要全库:CREATE PUBLICATION pub_all FOR ALL TABLES;

步骤 2 订阅端配置

-- postgresql.conf
max_logical_replication_workers = 4   -- 大于等于表数+1
max_sync_workers_per_subscription = 2

pg_ctl restart

-- 建同结构表
CREATE DATABASE demo;
\c demo
CREATE TABLE public.t1(id int PRIMARY KEY, info text, ts timestamp);

-- 创建订阅(会自动建立复制槽)
CREATE SUBSCRIPTION sub1
CONNECTION 'host=192.168.1.10 port=5432 dbname=demo user=repl password=pwd123'
PUBLICATION pub1;
-- 返回 NOTICE: created replication slot "sub1" on publisher  即成功

步骤 3 验证

-- 发布端
INSERT INTO t1(id,info) VALUES (1,'hello'),(2,'world');
UPDATE t1 SET info='postgres' WHERE id=1;

-- 订阅端
SELECT * FROM t1;
 id |   info   |             ts
----+----------+----------------------------
  1 | postgres | 2025-10-14 14:32:10.1023
  2 | world    | 2025-10-14 14:32:10.1023

四、常用管理命令

1.查看发布

SELECT * FROM pg_publication;
\dRp+          -- psql 快捷命令

2.查看订阅

SELECT * FROM pg_subscription;
\dRs+          -- psql 快捷命令
SELECT * FROM pg_stat_subscription;   -- 实时 LSN、延迟

3.加/减表

ALTER PUBLICATION pub1 ADD TABLE new_tbl;
ALTER PUBLICATION pub1 DROP TABLE old_tbl;
-- 订阅端立即生效,无需重建

4.暂停/重启同步

ALTER SUBSCRIPTION sub1 DISABLE;
ALTER SUBSCRIPTION sub1 ENABLE;

5.重新拷贝已有数据(表同步失败时)

ALTER SUBSCRIPTION sub1 REFRESH PUBLICATION;

6.删除

DROP SUBSCRIPTION sub1;   -- 先删订阅,复制槽会自动清理
DROP PUBLICATION pub1;

五、高级玩法速览

1.只复制部分操作

CREATE PUBLICATION insert_only FOR TABLE t1 WITH (publish = 'insert');

2.复制部分列(PG 15+)

CREATE PUBLICATION pub_col FOR TABLE t1 (id, info);  -- 订阅端表也必须只有这两列

3.行级过滤(PG 15+)

CREATE PUBLICATION pub_row FOR TABLE t1 WHERE (id > 1000);

4.级联复制

订阅端自己再建发布,供第三级节点订阅,实现“主→汇总→数仓”链式架构 。

六、常见坑与排查

1.订阅端表缺少 PK/UK → 初始同步极慢,apply 报错 “cannot update/delete without replica identity”

解决:给表加主键,或 ALTER TABLE … REPLICA IDENTITY FULL;(性能差)

2.DDL 不会自动同步

需要手动在订阅端执行,或使用事件触发器 + 自动化脚本。

3.复制槽卡住 → 主库 WAL 无限增长

监控:

SELECT slot_name, active, restart_lsn, pg_size_pretty(pg_wal_lsn_diff(pg_current_wal_lsn(), restart_lsn)) AS lag
FROM pg_replication_slots;

发现 inactive 且 lag 持续增大:检查订阅端网络、进程是否存活,必要时 DROP SUBSCRIPTION 重建。

4.大事务延迟高

逻辑复制要等事务提交才解码,单条大事务可能看到秒级延迟;尽量业务侧拆事务。

5.因冲突会产生错误,复制停止,它必须由用户手动解决

逻辑复制的行为与普通的DML操作类似,因为即使订阅者节点本地更改了数据,数据也将被更新。传入数据违反任何约束,如主键冲突,逻辑复制都将停止,这被称为冲突。当复制UPDATE或者DELETE操作时,丢失的数据不会产生冲突,这样的操作将被忽略。
冲突会产生错误,并会停止复制,它必须由用户手动解决。有关冲突的详细信息可以在订阅者的服务器日志中找到。

冲突的修复方法主要有以下两种

  • 方法一:通过修改订阅端的数据解决冲突。例如,INSERT违反了唯一约束时,可以先删除订阅端造成唯一约束冲突的记录,然后再使用ALTER SUBSCRIPTION name ENABLE让订阅继续。
  • 方法二:在订阅端调用pg_replication_origin_advance(node_nametext,pos pg_lsn)函数,node_name就是subscription name,“pos”指重新开始的LSN,从而跳过有冲突的事务。

七、逻辑复制的限制

逻辑复制的数据库版本限制有以下几种:

·数据源发布和订阅节点需要运行PostgreSQL 9.4+。
·复制源过滤和冲突检测需要PostgreSQL 9.5+。
·pglogical支持跨PostgreSQL主要版本之间的复制,但在订阅服务器上,不同版本之间进行复制时可能会出现问题。
·支持从旧版本复制到新版本,因为PostgreSQL具有向后兼容性,但只有有限的向前兼容性比较安全。

逻辑复制的其他限制主要有以下几种:

·DDL操作不支持复制,发布节点上发布表进行DDL操作后,DDL操作不会复制到订阅节点,需要在订阅节点对发布表手动执行DDL操作。
·序列本身不支持复制,当前逻辑复制仅支持普通表,序列、视图、物化视图、分区表、外部表等对象都不支持。
·TEMPORARY表和UNLOGGED表不会被复制。
·大对象(Large Object)字段不支持复制。
·表名与列名必须结构相同,列的数据类型也必须相同(除非类型隐式转换相同)。
·订阅端的表可以有更多的列,并且顺序可以不同,但是类型和列名必须相同。
·只有超级用户才有权限添加所有表。
·不支持双向复制。
·表必须有主键或者唯一约束,否则像UPDATE或者DELETE这样的操作无法被复制。

八、一句话总结

“发布端管 哪些表+哪些操作,订阅端管 连接+应用;表结构必须有主键,DDL 自己负责,其余就是标准 SQL 搞定。” 照上面 3 大步操作,10 分钟即可在测试环境跑通 PostgreSQL 逻辑复制。

posted @ 2026-05-19 11:06  数据库小白(专注)  阅读(52)  评论(0)    收藏  举报