openGauss中的锁超时

2020-10-28 17:15:06 浏览数 (1)

pg从9.3版本开始提供了lock_timeout参数用以指定锁超时时间,默认0,openGauss由于是基于9.2.4版本pg研发,所以没有这个参数,但是openGauss中存在两个参数控制着锁超时:lockwait_timeout,update_lockwait_timeout

对于这两个参数的解释如下:

lockwait_timeout:控制单个锁的最长等待时间。当申请的锁等待时间超过设定值时,系统会报错。

update_lockwait_timeout:允许并发更新参数开启情况下,该参数控制并发更新同一行时单个锁的最长等待时间。当申请的锁等待时间超过设定值时,系统会报错。

从字面意思和解释可以看到如果获取更新锁的时候走update_lockwait_timeout,如果不获取更新锁,那么走lockwait_timeout。

两个参数的默认值如下:

代码语言:javascript复制
postgres=# show update_lockwait_timeout;
 update_lockwait_timeout
-------------------------
 2min
(1 row)


postgres=# show lockwait_timeout;
 lockwait_timeout
------------------
 20min
(1 row)

下面来验证一下这两个参数的区别,为了减少测试时间,我们将update_lockwait_timeout设置为10s,将lockwait_timeout设置为20s。该参数只能写入postgresql.conf配置文件中。

场景1:两个事物update同一行

会话1:

代码语言:javascript复制
test=# begin;
BEGIN
test=# update test set id=2 where id=1;
UPDATE 1

会话2:

代码语言:javascript复制
test=# timing
Timing is on.
test=# update test set id=3 where id=1;
ERROR:  Lock wait timeout: thread 139785179494144 on node dn_6001_6002_6003 waiting for ShareLock on transaction 102055465 after 10002.340 ms
DETAIL:  blocked by hold lock thread 139785215145728, statement <update test set id=2 where id=1;>, hold lockmode ExclusiveLock.
Time: 10017.495 ms

可以看到这个并发更新的锁走的是update_lockwait_timeout参数。

场景2:select for update场景

会话1:

代码语言:javascript复制
test=# begin;
BEGIN
test=# update test set id=2 where id=1;
UPDATE 1

会话2:

代码语言:javascript复制
test=# select * from test where id=1 for update;
ERROR:  Lock wait timeout: thread 139785179494144 on node dn_6001_6002_6003 waiting for ShareLock on transaction 102055467 after 10000.174 ms
DETAIL:  blocked by hold lock thread 139785215145728, statement <update test set id=2 where id=1;>, hold lockmode ExclusiveLock.
Time: 10006.634 ms

可以看到select for update依旧走的是更新锁update_lockwait_timeout锁超时参数。

场景3:显式lock table

会话1:

代码语言:javascript复制
test=# begin;
BEGIN
test=# lock table test;
LOCK TABLE

会话2:

代码语言:javascript复制
test=# update test set id=3 where id=1;
ERROR:  Lock wait timeout: thread 139785179494144 on node dn_6001_6002_6003 waiting for RowExclusiveLock on relation 16386 of database 16385 after 20002.091 ms
LINE 1: update test set id=3 where id=1;
               ^
DETAIL:  blocked by hold lock thread 139785215145728, statement <lock table test;>, hold lockmode AccessExclusiveLock.
Time: 20008.300 ms
test=# select * from test;
ERROR:  Lock wait timeout: thread 139785179494144 on node dn_6001_6002_6003 waiting for AccessShareLock on relation 16386 of database 16385 after 20000.128 ms
LINE 1: select * from test;
                      ^
DETAIL:  blocked by hold lock thread 139785215145728, statement <lock table test;>, hold lockmode AccessExclusiveLock.
Time: 20006.237 ms

可以看到显式lock table时走的才是lockwait_timeout锁超时参数。

场景4:ddl

会话1:

代码语言:javascript复制
test=# begin;
BEGIN
test=# update test set id=2 where id=1;
UPDATE 1

会话2:

代码语言:javascript复制
test=# drop table test;
ERROR:  Lock wait timeout: thread 139785179494144 on node dn_6001_6002_6003 waiting for AccessExclusiveLock on relation 16386 of database 16385 after 20000.169 ms
DETAIL:  blocked by hold lock thread 139785215145728, statement <update test set id=2 where id=1;>, hold lockmode RowExclusiveLock.
Time: 20006.911 ms
test=# create index on test(id);
ERROR:  Lock wait timeout: thread 139785179494144 on node dn_6001_6002_6003 waiting for ShareLock on relation 16386 of database 16385 after 20000.102 ms
DETAIL:  blocked by hold lock thread 139785215145728, statement <update test set id=2 where id=1;>, hold lockmode RowExclusiveLock.
Time: 20006.578 ms

可以看到ddl等待锁的情况走的也是lockwait_timeout参数。

所以可以看到两个参数区别在于update_lockwait_tiemout在于控制并发更新同一行数据时的锁等待时间,而lockwait_timeout参数在于控制ddl锁等待以及显式lock table时的锁等待时间。

0 人点赞