暂无图片
暂无图片
1
暂无图片
暂无图片
暂无图片

PostgreSQL 逻辑复制开始时还未结束的事务是否会丢失?

digoal 2019-05-23
705

作者

digoal

日期

2019-05-23

标签

PostgreSQL , 逻辑复制 , decode , commit record , 什么时候解析事务logical record


背景

逻辑复制是从REDO解析LOGICAL变化量,在目标端回放的技术。

那么当我们开启逻辑复制时,如果有一个事务比开启逻辑复制时间点还要早,等这个事务提交的时候,逻辑复制能解析出它的REDO吗?

```
T1: begin transaction1

T2: 开始逻辑复制

T3: commit transaction1

逻辑复制是否会丢失transaction1 ?
```

首先这是个伪命题,因为开启逻辑复制时,就会等所有的事务结束,只有数据库中没有未提交事务的时候,逻辑复制才会开启。

我们来看一下例子。

验证

1、创建测试表

postgres=# create table abc(id int primary key, info text, crt_Time timestamp); CREATE TABLE postgres=# insert into abc values (1,'test',now()); INSERT 0 1

2、开启事务,写入一些数据

postgres=# begin; BEGIN postgres=# delete from abc; DELETE 1 postgres=# insert into abc values (2,'a',now()); INSERT 0 1 postgres=# insert into abc values (1,'test',now()); INSERT 0 1

3、在事务结束前,创建SLOT并准备开始接收增量

digoal@pg11-test-> pg_recvlogical --create-slot --slot digoal -f - -h 127.0.0.1 -p 8001 -d postgres -U postgres

你会发现,这个创建SLOT的人为无法执行下去。卡住

查看锁等待:

《PostgreSQL 锁等待监控 珍藏级SQL - 谁堵塞了谁》

postgres=# select * from pg_locks; locktype | database | relation | page | tuple | virtualxid | transactionid | classid | objid | objsubid | virtualtransaction | pid | mode | granted | fastpath ---------------+----------+----------+------+-------+------------+---------------+---------+-------+----------+--------------------+------+------------------+---------+---------- relation | 13285 | 1951123 | | | | | | | | 4/30251 | 2160 | RowExclusiveLock | t | t virtualxid | | | | | 4/30251 | | | | | 4/30251 | 2160 | ExclusiveLock | t | t relation | 13285 | 11645 | | | | | | | | 6/28 | 2293 | AccessShareLock | t | t virtualxid | | | | | 6/28 | | | | | 6/28 | 2293 | ExclusiveLock | t | t transactionid | | | | | | 1389716362 | | | | 5/0 | 2184 | ShareLock | f | f transactionid | | | | | | 1389716362 | | | | 4/30251 | 2160 | ExclusiveLock | t | f (6 rows)

堵塞2184(即pg_recvlogical)的是谁?

postgres=# select * from pg_blocking_pids(2184); -[ RECORD 1 ]----+------- pg_blocking_pids | {2160}

这两个PID当前的状态

-[ RECORD 4 ]----+------------------------------------------------------- datid | 13285 datname | postgres pid | 2160 usesysid | 10 usename | postgres application_name | psql client_addr | client_hostname | client_port | -1 backend_start | 2019-05-24 09:25:49.72042+08 xact_start | 2019-05-24 09:25:58.942292+08 query_start | 2019-05-24 09:26:02.38297+08 state_change | 2019-05-24 09:26:02.383449+08 wait_event_type | Client wait_event | ClientRead state | idle in transaction backend_xid | 1389716362 backend_xmin | query | insert into a values (1); backend_type | client backend -[ RECORD 5 ]----+------------------------------------------------------- datid | 13285 datname | postgres pid | 2184 usesysid | 10 usename | postgres application_name | pg_recvlogical client_addr | 127.0.0.1 client_hostname | client_port | 58566 backend_start | 2019-05-24 09:26:07.208524+08 xact_start | query_start | 2019-05-24 09:26:07.210115+08 state_change | 2019-05-24 09:26:07.210805+08 wait_event_type | Lock wait_event | transactionid state | active backend_xid | backend_xmin | query | SELECT pg_catalog.set_config('search_path', '', false) backend_type | walsender

使用《PostgreSQL 锁等待监控 珍藏级SQL - 谁堵塞了谁》 查询到等待如下:

-[ RECORD 1 ]-+----------------------------------------------------------------------------------------------------------------------------------------------------- locktype | transactionid datname | postgres relation | page | tuple | virtualxid | transactionid | 1389716362 classid | objid | objsubid | lock_conflict | Pid: 2160 + | Lock_Granted: true , Mode: ExclusiveLock , FastPath: false , VirtualTransaction: 4/30251 , Session_State: idle in transaction + | Username: postgres , Database: postgres , Client_Addr: NULL , Client_Port: -1 , Application_Name: psql + | Xact_Start: 2019-05-24 09:25:58.942292+08 , Query_Start: 2019-05-24 09:26:02.38297+08 , Xact_Elapse: 00:06:52.216284 , Query_Elapse: 00:06:48.775606+ | SQL (Current SQL in Transaction): + | insert into a values (1); + | -------- + | Pid: 2184 + | Lock_Granted: false , Mode: ShareLock , FastPath: false , VirtualTransaction: 5/0 , Session_State: active + | Username: postgres , Database: postgres , Client_Addr: 127.0.0.1/32 , Client_Port: 58566 , Application_Name: pg_recvlogical + | Xact_Start: NULL , Query_Start: 2019-05-24 09:26:07.210115+08 , Xact_Elapse: NULL , Query_Elapse: 00:06:43.948461 + | SQL (Current SQL in Transaction): + | SELECT pg_catalog.set_config('search_path', '', false)

top 如下

746 digoal 20 0 33.057g 33844 33332 S 0.0 0.0 0:02.51 postgres: walwriter 2184 digoal 20 0 33.062g 7208 5848 S 0.0 0.0 0:00.00 postgres: walsender postgres 127.0.0.1(58566) idle waiting 748 digoal 20 0 132300 1740 572 S 0.0 0.0 0:02.01 postgres: stats collector 2160 digoal 20 0 33.061g 276512 273268 S 0.0 0.1 0:00.11 postgres: postgres postgres [local] idle in transaction 2293 digoal 20 0 34.066g 420564 408068 R 99.0 0.1 0:32.98 postgres: postgres postgres [local] VACUUM 751 digoal 20 0 33.063g 4964 3596 S 0.0 0.0 0:02.10 postgres: logical replication worker for subscription 1932539 750 digoal 20 0 33.059g 2160 1140 S 0.0 0.0 0:01.52 postgres: logical replication launcher 742 digoal 20 0 124856 952 488 S 0.0 0.0 0:01.26 postgres: logger 744 digoal 20 0 33.058g 266844 266264 S 0.0 0.1 0:00.15 postgres: checkpointer 745 digoal 20 0 33.058g 265384 264864 S 0.0 0.1 0:02.66 postgres: background writer 747 digoal 20 0 33.059g 2192 1296 S 0.0 0.0 0:00.21 postgres: autovacuum launcher 2183 digoal 20 0 116688 1036 856 S 0.0 0.0 0:00.00 pg_recvlogical --create-slot --slot digoal -f - -h 127.0.0.1 -p 8001 -d postgres -U postgres 740 digoal 20 0 33.057g 856608 856100 S 0.0 0.2 0:04.17 /home/digoal/pgsql11.3/bin/postgres

当前等待有没有对其他事务造成危害呢?

因为上面两个等待的锁冲突出现在xactid层面,只是两个事务之间的冲突,所以并不影响其他事务。

```
postgres=# insert into a values (2);
INSERT 0 1

postgres=# create table hello (id int);
CREATE TABLE
postgres=# drop table hello;
DROP TABLE
```

只要等事务结束,创建SLOT就可以成功了。

4、提交事务

postgres=# end; COMMIT

5、创建SLOT成功

6、重新开启事务,并执行一些操作

postgres=# begin; BEGIN postgres=# insert into abc values (3,'test',now()); INSERT 0 1 postgres=# insert into abc values (4,'test',now()); INSERT 0 1

7、事务结束前,开启接收REDO的任务

pg_recvlogical --start --slot digoal -f - -h 127.0.0.1 -p 8001 -d postgres -U postgres

8、结束事务

commit

9、当事务结束后,解析到了这笔事务的REDO,如果在这个事务结束前,又产生了很多REOD,实际上这笔事务需要用到很早以前的REDO文件中去解析LOGICAL变化量。

因此逻辑复制还有优化空间,例如每个会话自己解析自己产生的REDO,变化时即解析并落地。但是这样就不好使用DECODING介入。因为PG是支持自定义decoding格式的。

BEGIN 1389716360 table public.abc: INSERT: id[integer]:3 info[text]:'test' crt_time[timestamp without time zone]:'2019-05-23 19:33:57.781548' table public.abc: INSERT: id[integer]:4 info[text]:'test' crt_time[timestamp without time zone]:'2019-05-23 19:33:57.781548' COMMIT 1389716360

小结

当我们开启逻辑复制时,如果有一个事务比开启逻辑复制时间点还要早,等这个事务提交的时候,逻辑复制能解析出它的REDO吗?

首先这是个伪命题,因为开启逻辑复制时,就会等所有的事务结束,只有数据库中没有未提交事务的时候,逻辑复制才会开启。

PostgreSQL 许愿链接

您的愿望将传达给PG kernel hacker、数据库厂商等, 帮助提高数据库产品质量和功能, 说不定下一个PG版本就有您提出的功能点. 针对非常好的提议,奖励限量版PG文化衫、纪念品、贴纸、PG热门书籍等,奖品丰富,快来许愿。开不开森.

9.9元购买3个月阿里云RDS PostgreSQL实例

PostgreSQL 解决方案集合

德哥 / digoal's github - 公益是一辈子的事.

digoal's wechat

文章转载自digoal,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论