一、前言
最近也是看着看着,看到了逻辑复制这块,事实上我很少接触过这块,所以就当练练手了。
参考:https://boringsql.com/posts/logication-replication-introduction/
这里我打算在一台虚拟机上部署两个PostgreSQL实例,搭建一个双向复制的数据回环场景,
当然想要看到数据回环的效果的话,当前的PostgreSQL版本必须低于16,这里我的版本是15。
二、搭建
开启两个会话,会话一初始化数据库目录15,会话二初始化数据库目录2-15
然后会话一 修改数据库目录中的配置文件,在文件中添加下面信息
wal_level = logical
max_replication_slots = 10
max_wal_senders = 10
listen_addresses = '*'
logging_collector = on
log_min_messages = info会话二 修改配置文件 添加下面信息,和会话一唯一区别在于端口不同
wal_level = logical
max_replication_slots = 10
max_wal_senders = 10
listen_addresses = '*'
logging_collector = on
log_min_messages = info
port=1921然后分别启动数据库,为了简单方便,等会在搭建的时候,我直接使用我的超级用户zxm,
更推荐的自然是创建专属的复制用户来干这些事情。
在搭建双向复制的之前,其实就是一个简单的逻辑复制搭建。
这里我在会话一创建logical_demo_publisher数据库,在会话二创建my_subscriber_db数据库。
两个数据库存在名为products的表,且表结构一致。
定义语句如下:
CREATE TABLE products (
name TEXT NOT NULL,
category TEXT,
price DECIMAL(10, 2) NOT NULL,
stock_quantity INT DEFAULT 0,
created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
description TEXT,
is_active BOOLEAN DEFAULT TRUE
);之后在会话一,往表中插入10行数据
INSERT INTO products (
name,
category,
price,
stock_quantity,
description,
is_active
)
SELECT
'Product Batch ' || s.id AS name,
CASE (s.id % 5)
WHEN 0 THEN 'Electronics'
WHEN 1 THEN 'Books'
WHEN 2 THEN 'Home Goods'
WHEN 3 THEN 'Apparel'
ELSE 'Miscellaneous'
END AS category,
ROUND((RANDOM() * 500 + 10)::numeric, 2) AS price,
FLOOR(RANDOM() * 200)::int AS stock_quantity,
'Auto-generated description for product ID ' || s.id || '. Lorem ipsum dolor sit amet, consectetur adipiscing elit.' AS description,
(s.id % 10 <> 0) AS is_active
FROM generate_series(1, 10) AS s(id);在数据准备完毕之后,让我们来搭建逻辑复制,其实也非常简单,就是一个发布,一个订阅
在会话一中执行下面语句,进行发布
CREATE PUBLICATION my_publication FOR TABLE products;运行如下图所示:

在会话二中,执行以下语句进行订阅(记得修改成对应的用户)
CREATE SUBSCRIPTION my_subscription
CONNECTION 'host=127.0.0.1 port=5432 user=zxm dbname=logical_demo_publisher'
PUBLICATION my_publication;执行完成之后,事实上对于表products的逻辑复制便以及成功搭建好了。
让我们在会话二查看一下表products中的相关数据总数是否和会话一中的一致。

可以看到的是数据条数是一致的。实际的逻辑就是logical_demo_publisher --> my_subscriber_db
接下来我们来完成双向复制,也就是my_subscriber_db --> logical_demo_publisher ,从而触发数据回环
会话二执行如下语句,进行发布的动作
CREATE PUBLICATION my_publication2 FOR TABLE products;会话一执行如下语句,(记得修改用户),执行订阅动作
CREATE SUBSCRIPTION my_subscription2
CONNECTION 'host=127.0.0.1 port=1921 user=zxm dbname=my_subscriber_db'
PUBLICATION my_publication2;然后分别在各自的会话,查询表中数据,如下所示:

然后就可以看到,虽然两个会话什么都没做,一个INSERT都没看到但是表中的数据在疯涨,这便出现了数据回环。
logical_demo_publisher <--> my_subscriber_db
三、如何解决这个问题
其实升级到16版本就没有这个问题的。或者是修改表结构新增一些逻辑来区分数据是哪里来的,通过触发器或者一些手段来解决。
但是可能有的朋友无法升级数据库的大版本,毕竟16版本在国内还是算的上是非常新的版本,同时也不想修改逻辑、表结构啥啥啥的。
下一篇我将介绍一个插件,来解决这个问题,敬请期待~
四、声明
若文中存在错误或不当之处,敬请指出,以便我进行修正和完善。希望这篇文章能够帮助到各位。
文章转载请联系,谢谢合作~
更多详细内容请阅读PostgreSQL官方文档~




