作者
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热门书籍等,奖品丰富,快来许愿。开不开森.