基于redis的分布式锁实现方法及系统与流程

文档序号:30170670发布日期:2022-05-26 10:20阅读:109来源:国知局
基于redis的分布式锁实现方法及系统与流程

1.本发明涉及微服务架构下java技术领域,具体地说是一种基于redis的分布式锁实现方法及系统。


背景技术:

2.在很多场景中,为了保证数据的最终一致性,需要很多的技术方案来支持,比如分布式锁。开发应用的时候,如果需要对某一个共享变量进行并发式访问的时候,可以用分布式锁进行处理。
3.为了保证一个方法或属性在高并发情况下的同一时间只能被一个访问者执行,在传统单体应用单机部署的情况下,可以使用并发处理相关的功能进行互斥控制。但是,随着业务发展的需要,原单体单机部署的系统被演化成分布式集群系统后,由于分布式系统多线程、多进程并且分布在不同机器上,这将使原单机部署情况下的并发控制锁策略失效,单纯的应用并不能提供分布式锁的能力。为了解决这个问题就需要一种跨机器的互斥机制来控制共享资源的访问,这就是分布式锁要解决的问题。
4.在很多互联网产品应用中,有些场景需要加锁处理,比如:秒杀,全局递增id,楼层生成等等。分布式锁是控制分布式系统之间同步访问共享资源的一种方式。如果不同的系统或是同一个系统的不同主机之间共享了一个或一组资源,那么访问这些资源的时候,往往需要通过一些互斥手段来防止彼此之间的干扰,以保证一致性,在这种情况下,就需要使用分布式锁了。大部分的解决方案是基于db实现的,但是普通的关系型数据库在读写性能上存在瓶颈。
5.故如何将redis分布式锁处理数据的并发访问,并保证数据的最终一致性是目前亟待解决的技术问题。


技术实现要素:

6.本发明的技术任务是提供一种基于redis的分布式锁实现方法及系统,来解决如何将redis分布式锁处理数据的并发访问,并保证数据的最终一致性的问题。
7.本发明的技术任务是按以下方式实现的,一种基于redis的分布式锁实现方法,该方法具体如下:
8.获取当前时间,以毫秒为单位;
9.按顺序向redis master节点请求加锁;
10.客户端设置网络连接和响应超时时间,响应超时时间小于锁的失效时间;若响应超时时间超时,跳过该redis master节点,尝试下一个redis master节点;
11.客户端使用当前时间减去开始获取锁时间,得到获取锁的使用时间:
12.当且仅当超过一半的redis master节点均获得锁,并且获取锁的使用时间小于锁失效时间时,锁获取成功;
13.当锁获取成功,获取锁(key)的真正有效时间需要减去获取锁使用的时间;
14.当锁获取失败,客户端在所有的redis master节点上解锁。
15.作为优选,获取锁时,使用setnx加锁,并使用expire命令为锁添加一个超时时间,超过该超时时间,则自动释放锁;其中,锁的value值为一个随机生成的uuid,通过锁的value值在释放锁时进行判断;
16.其中,setnx(setnx key val)具体为:当且仅当key不存在时,set一个key为val的字符串,返回1;若key存在,则什么都不做,返回0;
17.expire(expire key timeout)具体为:为key设置一个超时时间,单位为second,超过该超时时间锁会自动释放,避免死锁;
18.delete(delete key)具体为:删除key。
19.更优地,获取锁时,还设置一个获取的超时时间,若超过该超时时间,则放弃获取锁。
20.更优地,释放锁时,通过uuid判断是不是该锁,若是该锁,则执行delete进行锁释放。
21.作为优选,加锁具体如下:
22.通过set方法尝试加锁:
23.若当前锁不存在,返回加锁成功
24.若当前锁已经存在,则获取锁的过期时间,将获取锁的过期时间与当前时间比较:
25.若锁已经过期,则设置新的过期时间,返回加锁成功。
26.更优地,set方法具体为:
27.set(string key,string value,string nxxx,string expx,int time);
28.其中,参数key:使用key来当锁,key是唯一的;
29.参数value:这里传的是requestid,为了保证分布式锁的可靠性,通过给value赋值为requestid,来了解对应加锁的请求,为解锁提供依据,即就知道这把锁是哪个请求加的了,在解锁的时候就可以有依据;requestid使用uuid.randomuuid().tostring()方法生成;
30.参数nxxx:这个使用的是nx,意思是set if not exist,即当key不存在时,进行set操作;若key已经存在,则不做任何操作;
31.参数expx:这个参数传的是px,意思是要为key加一个过期的设置,具体时间由参数time决定;
32.参数time:与参数expx相呼应,代表key的过期时间。
33.作为优选,解锁具体如下:
34.获取锁对应的value值,检查是否与requestid相等:
35.若相等,则删除锁,即解锁;
36.若不相等,则直接结束执行。
37.其中,分布式锁是排他锁(exclusive locks),简称x锁,又称为写锁或独占锁,是一种基本的锁类型。如果事务t1对数据对象o1加上了排他锁,那么在整个加锁期间,只允许事务t1对o1进行读取和更新操作,其它任何事务都不能再对这个数据对象进行任何类型的操作——直到t1释放了排他锁。排他锁的核心是如何保证当前有且仅有一个事务获得锁,并且锁被释放后,所有正在等待获取锁的事务都能够被通知到。
38.分布式锁应该具备以下条件:
39.①
在分布式系统环境下,一个方法在同一时间只能被一个机器的一个线程执行;
40.②
高可用的获取锁与释放锁;
41.③
高性能的获取锁与释放锁;
42.④
具备可重入特性;
43.⑤
具备锁失效机制,防止死锁;
44.⑥
具备非阻塞锁特性,即没有获取到锁将直接返回获取锁失败。
45.本发明采用redis结合springboot作为分布式锁的实现。
46.一种基于redis的分布式锁实现系统,该系统包括,
47.获取模块,用于获取当前时间,以毫秒为单位;
48.请求模块,用于按顺序向redis master节点请求加锁;
49.设置模块,用于通过客户端设置网络连接和响应超时时间,响应超时时间小于锁的失效时间;若响应超时时间超时,跳过该redis master节点,尝试下一个redis master节点;
50.计算模块,用于用客户端使用当前时间减去开始获取锁时间,得到获取锁的使用时间:
51.判断模块,用于判断是否过一半的redis master节点均获得锁,并且获取锁的使用时间小于锁失效时间:
52.若是,则锁获取成功,获取锁(key)的真正有效时间需要减去获取锁使用的时间;
53.若否,则锁获取失败,客户端在所有的redis master节点上解锁。
54.一种电子设备,包括:存储器和至少一个处理器;
55.其中,所述存储器存储计算机执行指令;
56.所述至少一个处理器执行所述存储器存储的计算机执行指令,使得所述至少一个处理器执行如上述的基于redis的分布式锁实现方法。
57.一种计算机可读存储介质,其特征在于,所述计算机可读存储介质中存储有计算机执行指令,当处理器执行所述计算机执行时,实现如上述的基于redis的分布式锁实现方法。
58.本发明的基于redis的分布式锁实现方法及系统具有以下优点:
59.(一)本发明利用redis的特性,结合springboot,实现了一种分布式锁的应用,简化了后端应用的开发,提高传统方式的系统性能,进而提高系统稳定性,开关的模式使其更加灵活;其中,redis为单进程单线程模式,采用队列模式将并发访问变成串行访问,且多客户端对redis的连接并不存在竞争关系,其次redis提供一些命令setnx,getset,可以方便实现分布式锁机制;
60.(二)本发明使用redis实现的分布式锁具有很好的扩展性,可以很便捷的应对需求的变更和业务的扩展,但是对于简单的场景直接使用定时任务会更加容易;在有大量的分布式锁请求时,就可以考虑利用redis的集群特性部署更多的redis实例,让系统更具扩展性;
61.(三)本发明具有高效性,redis作为著名的开源key-value数据库,官方提供的测试数据为:读的速度是110000次/s,写的速度是81000次/s,并且这已经在许多实际场景中
得到了验证;
62.(四)本发明具有高可用性,redis支持多实例部署。挂掉一个实例后,还有后备实例继续提供服务;
63.(五)本发明具有实时性,redis主从同步机制确保锁信息可以及时的在各使用者之间同步。
附图说明
64.下面结合附图对本发明进一步说明。
65.附图1为基于redis的分布式锁实现方法的示意图。
具体实施方式
66.参照说明书附图和具体实施例对本发明的基于redis的分布式锁实现方法及系统作以下详细地说明。
67.实施例1:
68.如附图1所示,本发明的基于redis的分布式锁实现方法,该方法具体如下:
69.s1、获取当前时间,以毫秒为单位;
70.s2、按顺序向redis master节点请求加锁;
71.s3、客户端设置网络连接和响应超时时间,响应超时时间小于锁的失效时间(假设锁自动失效时间为10秒,则超时时间一般在5-50毫秒之间,我们就假设超时时间是50ms吧);若响应超时时间超时,跳过该redis master节点,尝试下一个redis master节点;
72.s4、客户端使用当前时间减去开始获取锁时间,得到获取锁的使用时间:
73.当且仅当超过一半(n/2+1,这里是5/2+1=3个节点)的redis master节点均获得锁,并且获取锁的使用时间小于锁失效时间时,锁获取成功(10s》30ms+40ms+50ms+4m0s+50ms);
74.当锁获取成功,获取锁(key)的真正有效时间需要减去获取锁使用的时间;
75.当锁获取失败(没有在至少n/2+1个master实例取到锁,有或者获取锁时间已经超过了有效时间),客户端在所有的redis master节点上解锁(即便有些master节点根本就没有加锁成功,也需要解锁,以防止有些漏网之鱼)。
76.本实施例中的获取锁时,使用setnx加锁,并使用expire命令为锁添加一个超时时间,超过该超时时间,则自动释放锁;其中,锁的value值为一个随机生成的uuid,通过锁的value值在释放锁时进行判断;
77.其中,setnx(setnx key val)具体为:当且仅当key不存在时,set一个key为val的字符串,返回1;若key存在,则什么都不做,返回0;
78.expire(expire key timeout)具体为:为key设置一个超时时间,单位为second,超过该超时时间锁会自动释放,避免死锁;
79.delete(delete key)具体为:删除key。
80.本实施例中的获取锁时,还设置一个获取的超时时间,若超过该超时时间,则放弃获取锁。
81.本实施例中的释放锁时,通过uuid判断是不是该锁,若是该锁,则执行delete进行
锁释放。
82.本实施例中的加锁具体如下:
83.通过set方法尝试加锁:
84.若当前锁不存在,返回加锁成功
85.若当前锁已经存在,则获取锁的过期时间,将获取锁的过期时间与当前时间比较:
86.若锁已经过期,则设置新的过期时间,返回加锁成功。
87.本实施例中的set方法具体为:
88.set(string key,string value,string nxxx,string expx,int time);
89.其中,参数key:使用key来当锁,key是唯一的;
90.参数value:这里传的是requestid,为了保证分布式锁的可靠性,通过给value赋值为requestid,来了解对应加锁的请求,为解锁提供依据,即就知道这把锁是哪个请求加的了,在解锁的时候就可以有依据;requestid使用uuid.randomuuid().tostring()方法生成;
91.参数nxxx:这个使用的是nx,意思是set if not exist,即当key不存在时,进行set操作;若key已经存在,则不做任何操作;
92.参数expx:这个参数传的是px,意思是要为key加一个过期的设置,具体时间由参数time决定;
93.参数time:与参数expx相呼应,代表key的过期时间。
94.本实施例中的解锁通过lua实现的脚本来完成。redis可以原子地执行lua脚本。这部分代码必须是原子性的,非原子性执行可能会导致以下这些问题:
95.这个代码的问题在于delete时,这把锁已经不属于当前客户端的时候会解除他人加的锁。那么是否真的有这种场景?答案是肯定的,比如客户端a加锁,一段时间之后客户端a解锁,在执行delete之前,锁突然过期了,此时客户端b尝试加锁成功,然后客户端a再执行delete方法,则将客户端b的锁给解除了。
96.解锁具体如下:
97.获取锁对应的value值,检查是否与requestid相等:
98.若相等,则删除锁,即解锁;
99.若不相等,则直接结束执行。
100.实施例2:
101.本发明的基于redis的分布式锁实现系统,该系统包括,
102.获取模块,用于获取当前时间,以毫秒为单位;
103.请求模块,用于按顺序向redis master节点请求加锁;
104.设置模块,用于通过客户端设置网络连接和响应超时时间,响应超时时间小于锁的失效时间;若响应超时时间超时,跳过该redis master节点,尝试下一个redis master节点;
105.计算模块,用于用客户端使用当前时间减去开始获取锁时间,得到获取锁的使用时间:
106.判断模块,用于判断是否过一半的redis master节点均获得锁,并且获取锁的使用时间小于锁失效时间:
107.若是,则锁获取成功,获取锁(key)的真正有效时间需要减去获取锁使用的时间;
108.若否,则锁获取失败,客户端在所有的redis master节点上解锁。
109.实施例3:
110.本发明还提供了一种电子设备,包括:存储器和至少一个处理器;
111.其中,所述存储器存储计算机执行指令;
112.所述至少一个处理器执行所述存储器存储的计算机执行指令,使得所述至少一个处理器执行本发明任一项所述的基于redis的分布式锁实现方法。
113.处理器可以是中央处理单元(cpu),还可以是其他通用处理器、数字信号处理器(dsp)、专用集成电路(asic)、现成可编程门阵列(fpga)或者其他可编程逻辑器件、分立门或者晶体管逻辑器件、分立硬件组件等。通过处理器可以是微处理器或者该处理器也可以是任何常规的处理器等。
114.存储器可用于储存计算机程序和/或模块,处理器通过运行或执行存储在存储器内的计算机程序和/或模块,以及调用存储在存储器内的数据,实现电子设备的各种功能。存储器可主要包括存储程序区和存储数据区,其中,存储程序区可存储操作系统、至少一个功能所需的应用程序等;存储数据区可存储根据终端的使用所创建的数据等。此外,存储器还可以包括高速随机存取存储器,还可以包括非易失性存储器,例如硬盘、内存、插接式硬盘,只能存储卡(smc),安全数字(sd)卡,闪存卡、至少一个磁盘存储期间、闪存器件、或其他易失性固态存储器件。
115.实施例4:
116.本发明还提供了一种计算机可读存储介质,其中存储有多条指令,指令由处理器加载,使处理器执行本发明任一实施例中的基于redis的分布式锁实现方法。具体地,可以提供配有存储介质的系统或者装置,在该存储介质上存储着实现上述实施例中任一实施例的功能的软件程序代码,且使该系统或者装置的计算机(或cpu或mpu)读出并执行存储在存储介质中的程序代码。
117.在这种情况下,从存储介质读取的程序代码本身可实现上述实施例中任何一项实施例的功能,因此程序代码和存储程序代码的存储介质构成了本发明的一部分。
118.用于提供程序代码的存储介质实施例包括软盘、硬盘、磁光盘、光盘(如cd-rom、cd-r、cd-rw、dvd-rom、dvd-ram、dvd-rw、dvd+rw)、磁带、非易失性存储卡和rom。可选择地,可以由通信网络从服务器计算机上下载程序代码。
119.此外,应该清楚的是,不仅可以通过执行计算机所读出的程序代码,而且可以通过基于程序代码的指令使计算机上操作的操作系统等来完成部分或者全部的实际操作,从而实现上述实施例中任意一项实施例的功能。
120.此外,可以理解的是,将由存储介质读出的程序代码写到插入计算机内的扩展板中所设置的存储器中或者写到与计算机相连接的扩展单元中设置的存储器中,随后基于程序代码的指令使安装在扩展板或者扩展单元上的cpu等来执行部分和全部实际操作,从而实现上述实施例中任一实施例的功能。
121.最后应说明的是:以上各实施例仅用以说明本发明的技术方案,而非对其限制;尽管参照前述各实施例对本发明进行了详细的说明,本领域的普通技术人员应当理解:其依然可以对前述各实施例所记载的技术方案进行修改,或者对其中部分或者全部技术特征进
行等同替换;而这些修改或者替换,并不使相应技术方案的本质脱离本发明各实施例技术方案的范围。
当前第1页1 2 
网友询问留言 已有0条留言
  • 还没有人留言评论。精彩留言会获得点赞!
1