我对 PostgreSQL 逻辑复制版本 15 有问题。(我也在 v10 和 v12 上测试过,但有同样的问题)。 测试需要复制,所以源数据库和目标数据库在同一台服务器上。
在我设置的配置文件中:
postgresql.conf
:
wal_level = logical # if I have "replica", I can't subscribe
pg_hba.conf
:
local replication all
host replication all 127.0.0.1/32 trust
host replication all ::1/128 trust
在我做的源数据库中:
CREATE PUBLICATION repl_name
FOR TABLE table1, table2, table3, ...;
在这个阶段的 pgAdmin 中我有:
CREATE PUBLICATION
Query returned successfully in 59 msec.
但是,在日志中,我对每个表都有一条消息:
2023-05-17 17:02:07.537 CEST [25356] ERROR: role "backup_user" does not exist
2023-05-17 17:02:07.537 CEST [25356] STATEMENT: GRANT SELECT ON SEQUENCE public.table1 TO backup_user;
这可能与以下事实有关:在我的计算机上,它正在从进行此复制的客户端还原备份。
但不知道有没有打扰到你,因为打字后:
select * from pg_catalog.pg_publication;
我可以看到我的出版物:
"20438" "stack_repl" "10" false true true true true false
但是我这里没看到:
select * from pg_stat_replication;
我觉得可能跟还没有订阅有关
真正的问题出现在我要订阅的时候。 首先,它用
table1
、table2
、table3
等表恢复数据库。自然地,表是空的。
我输入命令:
CREATE SUBSCRIPTION sub_test
CONNECTION 'dbname=dbname host=localhost port=5432 user=postgres password=12345'
PUBLICATION repl_name;
pgAdmin 无休止地旋转。即使我周末离开电脑,它也无法完成。
它显示在日志中:
2023-05-17 17:22:24.178 CEST [25376] LOG: logical decoding found initial starting point at 0/A0D6F338
2023-05-17 17:22:24.178 CEST [25376] DETAIL: Waiting for transactions (approximately 1) older than 3712 to end.
2023-05-17 17:22:24.178 CEST [25376] STATEMENT: CREATE_REPLICATION_SLOT "sub_test" LOGICAL pgoutput (SNAPSHOT 'nothing')
我向你保证,我已经为这个问题苦苦挣扎了很长时间,我需要支持/提示我可以做些什么来让数据开始复制。
您可能正在同一数据库集群中的两个数据库之间设置逻辑复制。这使得
CREATE SUBSCRIPTION
永远挂起,正如 文档 所描述的那样:
创建连接到同一数据库集群的订阅(例如,在同一集群中的数据库之间复制或在同一数据库内复制)只有在复制槽不是作为同一命令的一部分创建时才会成功。否则,
呼叫将挂起。为了使它工作,单独创建复制槽(使用函数CREATE SUBSCRIPTION
和插件名称pg_create_logical_replication_slot
)并使用参数pgoutput
创建订阅。这是一个实施限制,可能会在未来的版本中取消。create_slot = false
所以这就是成功之路:
连接到主数据库并创建插槽:
SELECT pg_create_logical_replication_slot('sub_test', 'pgoutput');
然后连接备库,运行:
CREATE SUBSCRIPTION sub_test
CONNECTION 'dbname=dbname host=localhost port=5432 user=postgres password=12345'
PUBLICATION repl_name
WITH (create_slot = false);