开发版本: 19 / devel
此文档适用于不受支持的 PostgreSQL 版本。
您可能需要查看当前版本的相同页面,或上面列出的其他受支持版本。

29.7. 序列复制 #

要将序列从发布端同步到订阅端,首先使用 CREATE PUBLICATION ... FOR ALL SEQUENCES 将它们发布,然后在订阅端执行:

执行上述任一订阅端命令后,都会启动一个 序列同步工作者,并在序列同步完成后退出。

启动序列同步工作者的数量受 max_sync_workers_per_subscription 配置项限制。

29.7.1. 序列定义不匹配 #

序列同步工作者会验证发布端和订阅端之间的序列定义是否一致。如果存在不匹配, 工作者会记录错误并退出。应用工作者会持续重新启动序列同步工作者,直到同步成功。 另见 wal_retrieve_retry_interval

要解决该问题,请使用 ALTER SEQUENCE 将订阅端的序列参数调整为与发布端一致。

29.7.2. 重新同步失配的序列 #

随着发布端推进,订阅端的序列值会变得不同步。

可以将订阅端上的 pg_subscription_rel.srsublsn 与发布端序列上的 pg_get_sequence_data 函数返回的 page_lsn 进行比较,以检测这种不同步。如果需要, 再执行 ALTER SUBSCRIPTION ... REFRESH SEQUENCES 重新同步。

Warning

每个序列在生成新的 WAL 记录之前,都会先在内存中缓存一批值(通常为 32 个), 因此只有在整个缓存批次用尽后,其 LSN 才会前进。结果是,如果序列增量仍落在同一 个缓存批次内(通常是 32 个值),就无法通过 LSN 比较检测到序列值漂移。

29.7.3. 示例 #

在发布端创建一些序列。

/* pub # */ CREATE SEQUENCE s1 START WITH 10 INCREMENT BY 1;
/* pub # */ CREATE SEQUENCE s2 START WITH 100 INCREMENT BY 10;

在订阅端创建相同的序列。

/* sub # */ CREATE SEQUENCE s1 START WITH 10 INCREMENT BY 1;
/* sub # */ CREATE SEQUENCE s2 START WITH 100 INCREMENT BY 10;

在发布端多次推进这些序列。

/* pub # */ SELECT nextval('s1');
 nextval
---------
      10
(1 row)
/* pub # */ SELECT nextval('s1');
 nextval
---------
      11
(1 row)
/* pub # */ SELECT nextval('s2');
 nextval
---------
     100
(1 row)
/* pub # */ SELECT nextval('s2');
 nextval
---------
     110
(1 row)

检查发布端上的序列页 LSN。

/* pub # */ SELECT * FROM pg_get_sequence_data('s1');
 last_value | is_called |  page_lsn
------------+-----------+------------
         11 | t         | 0/0178F9E0
(1 row)
/* pub # */ SELECT * FROM pg_get_sequence_data('s2');
 last_value | is_called |  page_lsn
------------+-----------+------------
        110 | t         | 0/0178FAB0
(1 row)

为这些序列创建发布。

/* pub # */ CREATE PUBLICATION pub1 FOR ALL SEQUENCES;

订阅该发布。

/* sub # */ CREATE SUBSCRIPTION sub1
/* sub - */ CONNECTION 'host=localhost dbname=test_pub application_name=sub1'
/* sub - */ PUBLICATION pub1;

验证初始序列值已同步。

/* sub # */ SELECT last_value, is_called FROM s1;
 last_value | is_called
------------+-----------
         11 | t
(1 row)

/* sub # */ SELECT last_value, is_called FROM s2;
 last_value | is_called
------------+-----------
        110 | t
(1 row)

确认发布端上的序列页 LSN 已记录到订阅端。

/* sub # */ SELECT srrelid::regclass, srsublsn FROM pg_subscription_rel;
 srrelid |  srsublsn
---------+------------
 s1      | 0/0178F9E0
 s2      | 0/0178FAB0
(2 rows)

再在发布端推进这些序列 50 次。

/* pub # */  SELECT nextval('s1') FROM generate_series(1,50);
/* pub # */  SELECT nextval('s2') FROM generate_series(1,50);

再次检查发布端上的序列页 LSN。

/* pub # */ SELECT * FROM pg_get_sequence_data('s1');
 last_value | is_called |  page_lsn
------------+-----------+------------
         61 | t         | 0/017CED28
(1 row)

/* pub # */ SELECT * FROM pg_get_sequence_data('s2');
 last_value | is_called |  page_lsn
------------+-----------+------------
        610 | t         | 0/017CEDF8
(1 row)

发布端和订阅端的序列页 LSN 不同,说明这些序列已经失配。使用 ALTER SUBSCRIPTION ... REFRESH SEQUENCES 重新同步订阅端已知的全部序列。

/* sub # */ ALTER SUBSCRIPTION sub1 REFRESH SEQUENCES;

再次检查订阅端上的序列。

/* sub # */ SELECT last_value, is_called FROM s1;
 last_value | is_called
------------+-----------
         61 | t
(1 row)

/* sub # */ SELECT last_value, is_called FROM s2;
 last_value | is_called
------------+-----------
        610 | t
(1 row)