Redis实现安全分布式锁的方法与流程

文档序号:32787899发布日期:2023-01-03 19:56阅读:25来源:国知局
Redis实现安全分布式锁的方法与流程
redis实现安全分布式锁的方法
技术领域
1.本发明涉及的是redis实现安全分布式锁的方法,属于分布式技术领域。


背景技术:

2.在分布式领域,不同进程可能同时共同访问、操作某个共享资源,如果不加锁控制的话,会出现很多意想不到的结果,导致数据不一致。
3.例如像电商秒杀场景,同一时刻,大量请求进来,如果不加锁的话,会出现下单数量和库存数量不匹配的情况,导致无法发货,这个时候就需要使用分布式锁。
4.redis是一款基于内存的key value缓存服务,是很合适用于分布式锁的实现的,加锁和解锁需要的开销成本极低,效率也非常高,还自带超时功能。基本原理是当某个线程需要操作某个领域的共享对象时,在redis中set该对象的唯一属性作为key,然后设置该key的超时时间,这个线程操作完以后,通过释放key来达到释放锁的目的。
5.参照redis官方文档,redis现有实现分布式锁的方案一般都是setnx(set if not exists)+expire方式,即先用setnx来抢锁,如果抢到之后,再用expire给锁设置一个过期时间,防止进程挂掉锁一直得不到释放,使用该方案的秒杀系统一种实施例如下图1所示,伪代码实现如下:
[0006][0007][0008]
虽然使用上述方案也可以实现分布式锁,但是它有几个缺点,首先,setnx和expire操作是分两步做的,不是一个原子性操作,如果某个进程setnx操作后挂机了,那么这个锁将永远无法得到释放。其次,还有一个缺点,就是当a线程获取到锁后,执行时间超过了设置的超时时间,当b线程再来获取锁的时候,可以获取到锁,在b线程执行过程中,a线程执行完了,然后释放了锁,这时候b线程处在无锁的状态下,如图2所示,这个过程可能会导致数据的不一致。


技术实现要素:

[0009]
本发明提出的是redis实现安全分布式锁的方法,其目的旨在克服现有技术存在的上述缺陷,保证分布式锁的有效性,保证数据的一致性。
[0010]
本发明的技术解决方案:redis实现安全分布式锁的方法,包括以下步骤:
[0011]
步骤s1:当客户a开始向系统发起业务请求,后端创建线程a执行该请求,通过业务对象某个属性作为key,创建的uuid作为value,设置超时时间,获取锁;
[0012]
步骤s2:线程a开始执行业务操作,因为某些原因线程a处理时间超过了设置的超时时间;
[0013]
步骤s3:客户b此时也向系统发起相同的业务请求,后端创建线程b执行该请求,这时线程a持有的锁已经超时,线程b同样通过同样业务对象的某个属性作为key,创建的uuid作为value,设置超时时间,获取锁;
[0014]
步骤s4:当线程a执行完毕后,通过之前生成的uuid来释放锁,发现redis中的缓存的uuid已改变,释放锁失败,事务回滚;
[0015]
步骤s5:线程b执行完毕后,通过线程b之前生成uuid来释放锁,释放成功,提交事务。
[0016]
优选的,获取锁和设置超时时间是原子性的,获取锁时设置当前线程的唯一随机值,线程释放锁时,根据当前线程的唯一随机值来释放。
[0017]
优选的,用lua脚本来保证setnx和expire的原子性。
[0018]
优选的,用redis的set指令扩展参数,set key value[ex seconds][px milliseconds][nx|xx]来保证setnx和expire的原子性。
[0019]
优选的,为每个线程获得锁的时候生成一个随机值uuid,在删除的时候,进行校验,用lua脚本合并判断逻辑与删除逻辑。
[0020]
本发明的优点:1)在大并发场景下,例如电商秒杀,通过原子性操作,保证分布式锁的有效性;
[0021]
2)谁获取锁,谁负责释放锁,保证了数据的一致性。
附图说明
[0022]
图1是现有技术redis实现分布式锁的方案的一种秒杀系统实施例示意图。
[0023]
图2是现有技术redis实现分布式锁的一种实施例流程图。
[0024]
图3是本发明redis实现安全分布式锁的一种实施例流程图。
具体实施方式
[0025]
下面结合实施例和具体实施方式对本发明作进一步详细的说明。
[0026]
为解决现有技术存在的上述问题,包含两个关键点,第一:保证setnx和expire操作是一个原子操作;第二:保证一个原则,谁获得锁,谁有资格释放锁。
[0027]
为保证以上第一个关键点,可以有两种解决方式,第一种是使用lua脚本来保证setnx和expire的原子性,lua脚本伪代码如下:
[0028][0029]
还有一种方式可以巧用redis的set指令扩展参数,set key value[ex seconds][px milliseconds][nx|xx],加锁伪代码如下:
[0030]
jedis.set(key,lock_value,”nx”,”ex”,100s)
[0031]
为保证以上第二个关键点,既然锁可能被别的线程误删,需要为每个线程获得锁的时候生成一个随机值uuid,在删除的时候,进行校验,伪代码如下:
[0032][0033]
由于上述判断是否是当前线程加的锁和释放锁不是一个原子操作,如果调用jedis.del()释放锁的时候,可能这把锁已经不属于当前客户端,会接触他人加的锁,为了严谨起见,也要用lua脚本代替,lua脚本伪代码如下:
[0034][0035]
通过给当前线程获取锁增加uuid随机值,加上lua脚本合并判断逻辑与删除逻辑,
保证了只有获取锁的线程才能释放锁,从而不会释放其他线程加的锁,保证了数据的一致性。调整后流程的示意图如图3所示。
[0036]
实施例
[0037]
整体加锁流程步骤如下:
[0038]
步骤s1:当客户a开始向系统发起秒杀商品的请求,后端创建线程a执行该请求,通过商品的某个属性作为key,创建的uuid作为value,设置超时时间,获取锁。
[0039]
步骤s2:线程a开始执行业务操作,可能因为某些原因,线程a处理时间超过了设置的超时时间。
[0040]
步骤s3:客户b这时也发起了秒杀同一个商品的请求,后端创建线程b执行该请求,这时线程a持有的锁已经超时,线程b同样通过商品的某个属性作为key,创建的uuid作为value,设置超时时间,获取锁。
[0041]
步骤s4:当线程a执行完毕后,通过之前生成的uuid来释放锁,发现redis中的缓存的uuid已经变了,释放锁失败,事务回滚。
[0042]
步骤s5:线程b执行完毕后,通过线程b之前生成uuid来释放锁,释放成功,提交事务。
[0043]
需要注意的是:
[0044]
1)获取锁和设置超时时间必须是原子性的;
[0045]
2)获取锁时,必须设置当前线程的唯一随机值;
[0046]
3)线程释放锁时,必须根据当前线程的唯一随机值来释放。
[0047]
以上所述的仅是本发明的优选实施方式,应当指出,对于本领域的普通技术人员来说,在不脱离本发明创造构思的前提下,还可以做出若干变形和改进,这些都属于本发明的保护范围。
当前第1页1 2 
网友询问留言 已有0条留言
  • 还没有人留言评论。精彩留言会获得点赞!
1