Redisson加锁流程
Redis分布式锁实现的三个核心要素
- 加锁:setnx(key,1)
- 解锁:del指令解锁需要放在finally里面执行
- 锁超时:expire(key, 30)
redis分布式锁常见问题及解决方法
- 锁需要有超时时间,防止死锁
expire lockkey 5 #给锁加上超时时间
- setnx和expire的非原子性
Redis 2.6.12以上版本为set指令增加了可选参数,伪代码如下: set(key,1,30,NX),这样就可以取代setnx指令。
- 超时后使用del 导致误删其他线程的锁
在加锁时可以把当前的线程ID当做value, 并在删除之前验证key对应的value是不是自己线程的ID。
- 锁超时出现并发安全问题
让获得锁的线程开启一个守护线程,用来给快要过期的锁续期。 可以使用redis客户端redisson,redisson很好的解决了redis在分布式环境下的一些棘手问题, 它的宗旨就是让使用者减少对Redis的关注,将更多精力放处理业务逻辑上。redisson对分布式锁做了很好封装,只需调用API即可。
RLock lock = redissonClient.getLock("stockLock") redisson在加锁成功后,会注册一个 timerTask 定时任务监听这个锁,每隔10秒就去查看这个锁,如果还持有锁,就对过期时间进行续期。 默认过期时间30秒。这个机制也被叫做 “看门狗”。
- 锁的可重入问题
给锁设置hash结构的加锁次数,每次加锁就+1,解锁-1,减到0为止锁就被释放了。
- 集群下分布式锁的问题
这个问题是在redis集群方案时会出现的。事实上,现在为了保证redis的?可?和访问性能,都会设置redis的主节点和从节点,主节点负责写操作,从节点负责读操作,也就意味着,我们所有的锁都要写在主redis服务器实例中,如果主redis服务器宕机,资源释放 (在没有加持久化时候,如果加了持久化,这个问题会更加复杂),此时redis主节点的数据并没有复制到从服务器,此时,其他客户端就会趁机获取锁,在之前拥有锁的客户端可能还在对资源进行操作,此时就会出现多客户端对同一资源进行访问和操作的问题。
解决方案:
使用redlock,原理与zookeeper分布式锁原理相同。多台主机超过半数设置成功则获取锁成功,要注意下主机个数必须是奇数,不过这有效率问题。