1

我创建了一个复制槽:

SELECT * FROM pg_create_logical_replication_slot('boxoffice_slot', 'test_decoding');

事务中的每个步骤在复制槽中都有自己的行。这是一个例子:

     lsn     |   xid   |     data
-------------+---------+---------------
 34A/7000028 | 1311904 | BEGIN 1311904
 34A/70020E0 | 1311904 | table cad.purchases: INSERT: id[integer]:754862
 34A/70020E1 | 1311904 | table cad.purchases: INSERT: id[integer]:754863
 34A/7000028 | 1311904 | COMMIT 1311904

问题:
在事务生命周期的哪个时刻,事务步骤开始写入复制槽?

是否有可能在事务提交之前将事务步骤写入复制槽?

换句话说,是否有可能在任何给定时间只有一半事务被写入复制槽,如下所示:

     lsn     |   xid   |     data
-------------+---------+---------------
 34A/7000028 | 1311904 | BEGIN 1311904
 34A/70020E0 | 1311904 | table cad.purchases: INSERT: id[integer]:754862

非常感谢您对此的见解。

4

3 回答 3

5

事务根本不会写入复制槽。它们被写入 WAL。肯定会发生只有部分事务写入 WAL 的情况,例如,如果处理被中断。

当会话结束时(或在服务器崩溃的恢复期间),部分写入的事务将自动标记为回滚。

复制槽不包含比 LSN(日志序列号)更多的数据。它们是在 WAL 中标记位置的持久数据结构。这样主服务器就不会丢弃消费者仍然需要的任何 WAL。当消费者处理 WAL 时,它会推进复制槽的 LSN,以便主节点可以丢弃已经使用的 WAL。

于 2019-12-06T07:47:40.727 回答
1

事务中的所有内容都在发生时写入复制槽。如果事务被回滚,则回滚被输入到 WAL。如果流在事务中间中断,则不会在订阅者端提交事务,至少在重新建立连接之前不会提交。

测试这一点的一种方法是创建一个复制槽,然后在另一个终端中,使用以下命令查看更改pg_recvlogical

pg_recvlogical -d postgres --slot <slot_name> --start --verbose -f -

如果你BEGIN是一个事务,创建一个表并在其中插入一百万行,你会看到write up toflush to值在增加,即使事务没有被提交/回滚。这告诉我们更改正在传播到接收端:

# pg_recvlogical -d postgres --slot regression_slot --start --verbose -f -
pg_recvlogical: starting log streaming at 0/0 (slot regression_slot)
pg_recvlogical: streaming initiated
pg_recvlogical: confirming write up to 0/0, flush to 0/0 (slot regression_slot)
pg_recvlogical: confirming write up to 0/DF5E620, flush to 0/DF5E620 (slot regression_slot)
pg_recvlogical: confirming write up to 0/DF5E620, flush to 0/DF5E620 (slot regression_slot)
pg_recvlogical: confirming write up to 0/12E01AB8, flush to 0/12E01AB8 (slot regression_slot)
pg_recvlogical: confirming write up to 0/12E01AF0, flush to 0/12E01AF0 (slot regression_slot)

此外,如果您pg_current_wal_lsn()在事务结束之前和之后在终端中查看,您会看到 LSN 增加了,即使您回滚了:

 pg_current_wal_lsn 
--------------------
 0/DF5E620
(1 row)

postgres=# begin;
BEGIN
postgres=# select pg_current_wal_lsn();
 pg_current_wal_lsn 
--------------------
 0/DF5E620
(1 row)

postgres=# insert into abc values (generate_series(1,1000000),'foobar');
INSERT 0 1000000
postgres=# select pg_current_wal_lsn();
 pg_current_wal_lsn 
--------------------
 0/1243C000
(1 row)

postgres=# rollback;
ROLLBACK
postgres=# select pg_current_wal_lsn();
 pg_current_wal_lsn 
--------------------
 0/12E01AB8
(1 row)
于 2019-12-05T22:08:08.567 回答
0

基于以下测试,我得出结论,事务只有在提交后才会插入到复制槽中。

testing=# BEGIN;
BEGIN
testing=# SELECT * FROM pg_logical_slot_get_changes('testing_slot', NULL, NULL);
 lsn | xid | data
-----+-----+------
(0 rows)

testing=# insert into person values (generate_series(1,10));
INSERT 0 10
testing=# SELECT * FROM pg_logical_slot_get_changes('testing_slot', NULL, NULL);
 lsn | xid | data
-----+-----+------
(0 rows)

testing=# COMMIT;
COMMIT
testing=# SELECT * FROM pg_logical_slot_get_changes('testing_slot', NULL, NULL);
    lsn     |   xid    |                           data
------------+----------+-----------------------------------------------------------
 D/23426BC0 | 16171153 | BEGIN 16171153
 D/23426BC0 | 16171153 | table public.person: INSERT: name[character varying]:'1'
 D/23427078 | 16171153 | table public.person: INSERT: name[character varying]:'2'
 D/234270B8 | 16171153 | table public.person: INSERT: name[character varying]:'3'
 D/234270F8 | 16171153 | table public.person: INSERT: name[character varying]:'4'
 D/23427138 | 16171153 | table public.person: INSERT: name[character varying]:'5'
 D/23427178 | 16171153 | table public.person: INSERT: name[character varying]:'6'
 D/234271B8 | 16171153 | table public.person: INSERT: name[character varying]:'7'
 D/234271F8 | 16171153 | table public.person: INSERT: name[character varying]:'8'
 D/23427238 | 16171153 | table public.person: INSERT: name[character varying]:'9'
 D/23427278 | 16171153 | table public.person: INSERT: name[character varying]:'10'
 D/23427320 | 16171153 | COMMIT 16171153
(12 rows)
于 2019-12-06T18:41:44.483 回答