决战圣地玛丽乔亚Day50--Redis实现分布式锁
分布式锁的最简单版本: setnx key value
set key value 命令是对key设置值的命令,不管key是否存在值都会设置进去。
setnx key value命令对key进行值的设置前进行非空判断,如果key有值返回0,如果key为空就设置返回1.
在setnx失败后会循环等待锁的释放:

缺点:没有对超时进行限制,如果在delete之前进行宕机,那么锁永远不会释放出去,那么就一直超时等待。
升级版本:给key设置一个超时时间
set key value ex 多少秒 nx
nx 表示该set命令具备setnx的特性。
如:set key eminent ex 60 nx 对key eminent设置60s过期时间,具备setnx特性

但是会出现一个问题,设置的60s内,如果业务流程较长的情况下,超出了60s。线程A释放key后,线程B获取了分布式锁执行任务。当线程A业务流程走完后删除锁
删除的是线程B的锁。锁的获取和删除都是通过锁的名称来进行分辨,所以在此基础上,我们需要加一个线程判断:
我们可以把set key eminent ex 60 nx 命令的锁的名称设置为当前线程的唯一标识,这样我们在删除的时候,对锁的名称进行一次判断即可解决这个问题。

业务逻辑执行超时的情况下:

新的问题是:
判断锁是否是当前线程和释放锁的操作不是原子性操作。就可能会导致,判断完确定释放后进行卡顿,卡顿期间线程B获取锁,恢复卡顿后,删除的是别的线程的锁。

最终版本:通过Lua脚本保证判断线程和执行操作的原子性。

我们可以通过Lua脚本在加锁的时候解决不可重入的问题。
在Lua脚本中先判断锁(key)是否存在,如果存在则再判断持有这把锁的线程是否是当前线程,如果不是则加锁失败,否则当前线程再次持有这把锁,并把锁的重入次数+1。在释放锁时,也是先判断持有锁的线程是否是当前线程,如果是则将锁的重入次数-1,直至重入次数减至0,即可删除该锁(key)。


浙公网安备 33010602011771号