advisory lock 实现高并发非堵塞式 业务锁-阿里云开发者社区

开发者社区> 德哥> 正文

advisory lock 实现高并发非堵塞式 业务锁

简介:
+关注继续查看

标签

PostgreSQL , advisory lock , 锁


背景

某些业务会利用数据库来作为一种可靠的锁,例如任务调度系统,或者其他需要可靠的锁机制的系统。

通常他们可能会使用数据库的一条记录来实现锁的SLOT和状态信息。

例如

create table lock_test (  
  tid int primary key,   -- 任务ID  
  state int default 1,   -- 任务状态,1表示初始状态,-1表示正在处理, 0表示处理结束  
  retry int default -1,   -- 重试次数  
  info text,   -- 其他信息  
  crt_time timestamp  -- 时间  
);  

任务处理系统到数据库获取任务

例如

update lock_test set state=-1 , retry=retry+1 where tid=? and state=1;  

处理失败

update lock_test set state=1 where tid=? and state=-1;  

处理成功

update lock_test set state=0 where tid=? and state=-1;  

当多个客户端并行获得同一个任务时,就会引发冲突,导致等待(虽然等待时间可能不长,但是在大型任务调度系统中,一点点的等待都无法忍受)。

如何解决这个冲突等待呢?

advisory lock登场,实际上在秒杀业务中我们也看到了它的踪影。

《PostgreSQL 使用advisory lock实现行级读写堵塞》

《PostgreSQL 无缝自增ID的实现 - by advisory lock》

《PostgreSQL 使用advisory lock或skip locked消除行锁冲突, 提高几十倍并发更新效率》

《聊一聊双十一背后的技术 - 不一样的秒杀技术, 裸秒》

advisory lock 实现高并发非堵塞式 业务锁

事务级或会话级,根据业务形态选择。

                                        List of functions  
   Schema   |               Name               | Result data type | Argument data types |  Type    
------------+----------------------------------+------------------+---------------------+--------  
 pg_catalog | pg_try_advisory_lock             | boolean          | bigint              | normal  
 pg_catalog | pg_try_advisory_xact_lock        | boolean          | bigint              | normal  

SQL改造如下

开始处理任务

update lock_test set state=-1 , retry=retry+1 where tid=? and state=1 and pg_try_advisory_xact_lock(?) returning *;  

处理失败

update lock_test set state=1 where tid=? and state=-1 and pg_try_advisory_xact_lock(?);  

处理成功

update lock_test set state=0 where tid=? and state=-1 and pg_try_advisory_xact_lock(?);  

性能压测对比

为了体现冲突的问题,我们使用一条记录来表示一个任务,大家都来抢一个任务的极端场景。

create table lock_test (  
  tid int primary key,   -- 任务ID  
  state int default 1,   -- 任务状态,1表示初始状态,-1表示正在处理, 0表示处理结束  
  retry int default -1,   -- 重试次数  
  info text,   -- 其他信息  
  crt_time timestamp  -- 时间  
);  
  
insert into lock_test values (1, 1, -1, 'test', now());  

1、传统模式压测

vi test1.sql  
  
update lock_test set state=-1 , retry=retry+1 where tid=1 and state=1;  
update lock_test set state=1 where tid=1 and state=-1;  
  
pgbench -M prepared -n -r -P 1 -f ./test1.sql -c 64 -j 64 -T 120  
  
query mode: prepared  
number of clients: 64  
number of threads: 64  
duration: 120 s  
number of transactions actually processed: 966106  
latency average = 7.940 ms  
latency stddev = 6.840 ms  
tps = 8050.081170 (including connections establishing)  
tps = 8054.812052 (excluding connections establishing)  
script statistics:  
 - statement latencies in milliseconds:  
         3.978  update lock_test set state=-1 , retry=retry+1 where tid=1 and state=1;  
         3.962  update lock_test set state=1 where tid=1 and state=-1;  

2、advisory lock模式压测

vi test2.sql  
  
update lock_test set state=-1 , retry=retry+1 where tid=1 and state=1 and pg_try_advisory_xact_lock(1) returning *;  
update lock_test set state=1 where tid=1 and state=-1 and pg_try_advisory_xact_lock(1);  
  
pgbench -M prepared -n -r -P 1 -f ./test2.sql -c 64 -j 64 -T 120  
  
query mode: prepared  
number of clients: 64  
number of threads: 64  
duration: 120 s  
number of transactions actually processed: 23984594  
latency average = 0.320 ms  
latency stddev = 0.274 ms  
tps = 199855.983575 (including connections establishing)  
tps = 199962.502494 (excluding connections establishing)  
script statistics:  
 - statement latencies in milliseconds:  
         0.163  update lock_test set state=-1 , retry=retry+1 where tid=1 and state=1 and pg_try_advisory_xact_lock(1) returning *;  
         0.156  update lock_test set state=1 where tid=1 and state=-1 and pg_try_advisory_xact_lock(1);  

8000 TPS提升到20万 TPS。开不开心、意不意外。

小结

1、使用advisory lock时,需要注意一点,因为它是库级别的轻量级锁,所以对于不同的业务(无需相互堵塞的业务),建议设计不同的advisory lock的ID空间,例如A业务的LOCK空间是1-1000000, B业务的LOCK空间是1000001-2000000的空间。诸如此类等等。

2、update, insert, delete都带returning语法,可以返回NEW, OLD value。

3、advisory 的其他应用:

《PostgreSQL 使用advisory lock实现行级读写堵塞》

《PostgreSQL 无缝自增ID的实现 - by advisory lock》

《PostgreSQL 使用advisory lock或skip locked消除行锁冲突, 提高几十倍并发更新效率》

《聊一聊双十一背后的技术 - 不一样的秒杀技术, 裸秒》

4、advisory lock的级别分事务级和会话级,根据业务的需求进行选择。

版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

相关文章
java 并发——理解 wait / notify / notifyAll
java 并发——理解 wait / notify / notifyAll一、前言前情简介:java 并发——内置锁java 并发——线程 java 面试是否有被问到过,sleep 和 wait 方法的区别,关于这个问题其实不用多说,大多数人都能回答出最主要的两点区别: sleep 是线程的方法, wait / notify / notifyAll 是 Object 类的方法;sleep 不会释放当前线程持有的锁,到时间后程序会继续执行,wait 会释放线程持有的锁并挂起,直到通过 notify 或者 notifyAll 重新获得锁。
1634 0
Node.js Serverless 助力业务研发提效 38.89%,并保障双11大流量下稳定可靠
本文将介绍我们在淘系双十一,从日常开发到作战的方案与经验,为大家提供一些 Node.js Serverless 的经验参考,也欢迎大家提出宝贵的意见。
724 0
阿里云企业级服务器怎么样?是否能满足高并发计算等需求?
阿里云企业级服务器怎么样?是否能满足高并发计算等需求?阿里云提供10大类等计算实例满足不同阶段的业务需求今天我们就来说下这10大类企业级X86计算通用型:CPU与内存比为1:4,适合各种均衡资源消耗应用场景。
1600 0
Tomcat 9.0.26 高并发场景下DeadLock问题排查与修复
本文主要针对deadlock问题进行分析以及通过使用Apache提供的新patch进行验证。
1349 0
+关注
德哥
公益是一辈子的事, I'm digoal, just do it.
2153
文章
245
问答
来源圈子
更多
阿里云数据库:帮用户承担一切数据库风险,给您何止是安心!支持关系型数据库:MySQL、SQL Server、PostgreSQL、PPAS(完美兼容Oracle)、自研PB级数据存储的分布式数据库Petadata、自研金融级云数据库OceanBase支持NoSQL数据库:MongoDB、Redis、Memcache更有褚霸、丁奇、德哥、彭立勋、玄惭、叶翔等顶尖数据库专家服务。
+ 订阅
文章排行榜
最热
最新
相关电子书
更多
《2021云上架构与运维峰会演讲合集》
立即下载
《零基础CSS入门教程》
立即下载
《零基础HTML入门教程》
立即下载