PostgreSQL逻辑复制中跳过事务

5
在我们公司中,我们使用逻辑复制(源服务器和接收器都是Postgresql 10.5版本),有时逻辑复制会因为错误而停止运行: ERROR: 重复的键值违反了唯一约束。

在pg_replication_origin_status中,我看到位置remote_lsn(它是源服务器上接收器达到的一个位置)。我知道如何使用pg_replication_origin_advance函数,并且我知道这个函数可能会跳过一些数据。是否有解决方案可以获取remote_lsn之后的下一个位置,以便数据不会丢失?


欢迎来到StackOverflow,我们很乐意为您提供帮助。为了提高您获得答案的机会,以下是一些提示:https://stackoverflow.com/help/how-to-ask - Dumi
你尝试过查看PostgreSQL邮件列表吗?你需要找的是pgsql-general。核心开发人员会监控该列表,这听起来像是你可能遇到了复制错误。 - Miles Elam
2个回答

4

你是否确定是哪个表导致了这个问题?通常是由使用序列的表定义引起的。在PostgreSQL中,序列不会被复制。目标服务器可以尝试从头开始启动序列,并为序列生成值1。这是因为逻辑复制不会复制序列的值,因为序列的下一个值不存储在表本身中。

解决方法:

  • 使用类似zookeeper的外部来源获取数字
  • 为不同服务器使用不重叠的范围

1
这是因为 PostgreSQL 中序列的工作方式:
考虑源表中有一个序列的情况:
src=# CREATE TABLE s (a serial PRIMARY KEY, b text);
CREATE TABLE
src=# INSERT INTO s (b) VALUES ('foo'), ('bar'), ('baz');
INSERT 0 3
src=# SELECT * FROM s;
 a |  b
---+-----
 1 | foo
 2 | bar
 3 | baz
(3 rows)

src=# SELECT currval('s_a_seq'), nextval('s_a_seq');
 currval | nextval
---------+---------
       3 |       4
(1 row)

序列s_a_seq被创建来支持serial类型的a列。这将为s.a生成自增值。现在让我们将其复制到dst,并插入另一行:

dst=# SELECT * FROM s;
 a |  b
---+-----
 1 | foo
 2 | bar
 3 | baz
(3 rows)

dst=# INSERT INTO s (b) VALUES ('foobaz');
ERROR:  duplicate key value violates unique constraint "s_pkey"
DETAIL:  Key (a)=(1) already exists.
dst=#  SELECT currval('s_a_seq'), nextval('s_a_seq');
 currval | nextval
---------+---------
       1 |       2
(1 row)

哎呀,刚才发生了什么?目标尝试从头开始启动序列,并为a生成值1。这是因为逻辑复制不会复制序列的值,因为序列的下一个值并未存储在表本身中。

解决方法

如果您从逻辑上考虑,您无法在两个位置修改相同的“自增”值而不进行双向同步。如果您确实需要在表的每一行中使用递增数字,并且需要从多个服务器插入到该表中,您可以:

  • 使用外部源来获取数字,例如ZooKeeper或etcd,
  • 使用非重叠范围-例如,第一个服务器在1到100万的范围内生成和插入数字,第二个服务器在100万到200万的范围内生成和插入数字,依此类推。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接