redis实现分布式锁
1.原生redis实现
2基于redisson实现
1基于原生redis实现
1.1redis的 命令Setnx+lua命令来实现
1. setnx key value #获取锁 要做唯一判断
2.lua脚本实现key的过期,从而保证原子性
if redis.call("get",KEYS[1])==ARGV[1] then
retrun redis.call("del",KEYS[1])
else
return 0
end
1.2 redis的set命令实现
在Redis 2.6.12 之后,对set进行了升级,通过新的set命令能够实现 setnx命令和psetex
SET key value [EX seconds] [PX milliseconds] [NX|XX]
官网解释链接:http://redisdoc.com/string/set.html
EX seconds
: 将键的过期时间设置为seconds
秒。 执行SET key value EX seconds
的效果等同于执行SETEX key seconds value
。PX milliseconds
: 将键的过期时间设置为milliseconds
毫秒。 执行SET key value PX milliseconds
的效果等同于执行PSETEX key milliseconds value
。NX
: 只在键不存在时, 才对键进行设置操作。 执行SET key value NX
的效果等同于执行SETNX key value
。XX
: 只在键已经存在时, 才对键进行设置操作
通过这个命令就可以很好的设置锁和锁的过期时间,而且还是原子性
-
set命令要用
set key value px milliseconds nx 设置锁的过期时间,防止死锁出现
; -
value要具有唯一性;
-
释放锁时要验证value值,不能误解锁;
这个实现存在的一些问题
1.redis 在线程没有执行完的情况下,key到期 锁失效,会发生多线程对一个方法操作
解决方案:锁续命: 在线程获取锁的时候,为获取当前锁的线程,在开启一个守护线程,用来给锁进行续命,从而解决锁的 到期时间
2.线程一直运行,一直续命会不会导致线程阻塞
解决思路:程序一直运行,锁线程肯定会一直续命,这里我们可以给锁续命,增加续命上限,但续命次数到达上线之后,就
3.在Redis的master节点上拿到了锁,但是这个加锁的key还没有同步到slave节点,master故障,发生故障转移,slave节点升级为master节点,导致锁丢失。
2.通过redission来实现分布式锁
redisson 是很好的解决分布式锁的一个问题
RLock lock = redisson.getLock(UUID.randomUUID().toString()); #获取锁
- lock.tryLock(); # 加锁 这是默认的设置30秒 过期
- lock.tryLock(long time, TimeUnit unit) #根据自己的逻辑来设置过期时间
- lock.unlock(); # 解锁