在同一个实例(cluster)的两个不同库(database)中进行逻辑同步

文章目录

  • 配置文件 pg_hba.conf
  • 实例
  • 实际操作过程
  • 参考:

说明: 默认创建发布时会创建对应的复制槽, 但是根据官方文档, 使用一般的方式在同一个 cluster 中创建发布之后, 再在另一个 database 中创建订阅时会hang 住,除非单独使用 pg_create_logical_replication_slot 创建独立的复制槽,并且
在创建订阅的时候, 使用创建的复制槽并使用参数 create_slot=false

Creating a subscription that connects to the same database cluster 
(for example, to replicate between databases in the same cluster or to 
replicate within the same database) will only succeed if the replication slot 
is not created as part of the same command. Otherwise, the CREATE SUBSCRIPTION 
call will hang. To make this work, create the replication slot separately 
(using the function pg_create_logical_replication_slot with the plugin name 
pgoutput) and create the subscription using the parameter create_slot = false.

配置文件 pg_hba.conf

local   replication     all                                     trust
host    replication     all             127.0.0.1/32            trust
host    replication     all             ::1/128                 trust

实例

# test
-- drop owned by repl;
-- drop user repl;
-- 创建逻辑复制用户
create user repl with replication password 'repl';

-- 创建测试表
create table t1(id bigserial primary key, info  text);
insert into t1(info) values('info1'),('info2'),('info3');
select * from t1;
-- 授权给逻辑复制用户
grant select on t1 to repl;

-- 创建发布
create publication pub1 for table t1;
-- 创建复制槽
select * from pg_create_logical_replication_slot('slot1','pgoutput') ;


# test2
-- test2 库中创建同名表
create table t1(id bigserial primary key, info  text);
-- 创建订阅
create subscription sub1 connection 'dbname=test host=127.0.0.1 port=1921 user=repl' publication pub1 with (slot_name=slot1,create_slot=false);
select * from t1;

# test
delete from t1 where id=1;
select * from t1;
c test2
select * from t1;
c test
update t1 set info='xxx' where id=2;
select * from t1;
c test2
select * from t1;

实际操作过程

test=# create user repl with replication password 'repl';
CREATE ROLE
test=# create table t1(id bigserial primary key, info  text);
CREATE TABLE
test=# insert into t1(info) values('info1'),('info2'),('info3');
INSERT 0 3
test=# select * from t1;
 id | info  
----+-------
  1 | info1
  2 | info2
  3 | info3
(3 rows)

test=# grant select on t1 to repl;
GRANT
test=# 
test=# 
test=# create publication pub1 for table t1;
CREATE PUBLICATION
test=# 
test=# select * from pg_create_logical_replication_slot('slot1','pgoutput') ;
 slot_name |    lsn    
-----------+-----------
 slot1     | 0/1A33080
(1 row)

test=# c test2
You are now connected to database "test2" as user "postgres".
test2=# create table t1(id bigserial primary key, info  text);
CREATE TABLE
test2=# create subscription sub1 connection 'dbname=test host=127.0.0.1 port=1921 user=repl' publication pub1 with (slot_name=slot1,create_slot=false);
CREATE SUBSCRIPTION
test2=# select * from t1;
 id | info  
----+-------
  1 | info1
  2 | info2
  3 | info3
(3 rows)

test2=# c test
You are now connected to database "test" as user "postgres".
test=# 
test=# 
test=# select * from t1;
 id | info  
----+-------
  1 | info1
  2 | info2
  3 | info3
(3 rows)

test=# delete from t1 where id=1;
DELETE 1
test=# select * from t1;
 id | info  
----+-------
  2 | info2
  3 | info3
(2 rows)

test=# c test2
You are now connected to database "test2" as user "postgres".
test2=# select * from t1;
 id | info  
----+-------
  2 | info2
  3 | info3
(2 rows)

test2=# c test
You are now connected to database "test" as user "postgres".

test=# update t1 set info='xxx' where id=2;
UPDATE 1
test=# select * from t1;
 id | info  
----+-------
  3 | info3
  2 | xxx
(2 rows)

test=# c test2
You are now connected to database "test2" as user "postgres".
test2=# select * from t1;
 id | info  
----+-------
  3 | info3
  2 | xxx
(2 rows)

参考:

https://stackoverflow.com/questions/59492957/can-i-have-a-logical-replication-between-2-databases-in-the-same-postgres-server
https://www.postgresql.org/docs/14/sql-altersubscription.html