在我们公司中,我们使用逻辑复制(源服务器和接收器都是Postgresql 10.5版本),有时逻辑复制会因为错误而停止运行:
ERROR: 重复的键值违反了唯一约束。
在pg_replication_origin_status中,我看到位置remote_lsn(它是源服务器上接收器达到的一个位置)。我知道如何使用pg_replication_origin_advance函数,并且我知道这个函数可能会跳过一些数据。是否有解决方案可以获取remote_lsn之后的下一个位置,以便数据不会丢失?
你是否确定是哪个表导致了这个问题?通常是由使用序列的表定义引起的。在PostgreSQL中,序列不会被复制。目标服务器可以尝试从头开始启动序列,并为序列生成值1。这是因为逻辑复制不会复制序列的值,因为序列的下一个值不存储在表本身中。
解决方法:
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。这是因为逻辑复制不会复制序列的值,因为序列的下一个值并未存储在表本身中。
解决方法
如果您从逻辑上考虑,您无法在两个位置修改相同的“自增”值而不进行双向同步。如果您确实需要在表的每一行中使用递增数字,并且需要从多个服务器插入到该表中,您可以: