Redis实现分布式锁
锁的种类
- 单机版同一个JVM虚拟机内,synchronized或者Lock接口
- 分布式不同个JVM虚拟机内,单机的线程锁机制不再起作用,资源类在不同的服务器之间共享了。
一个靠谱分布式锁需要具备的条件和刚需
- 独占性:OnlyOne,任何时刻只能有且仅有一个线程持有
- 高可用:若redis集群环境下,不能因为某一个节点挂了而出现获取锁和释放锁失败的情况
- 防死锁:杜绝死锁,必须有超时控制机制或者撤销操作,有个兜底终止跳 出方案
- 不乱抢:防止张冠李戴,不能私下unlock别人的锁,只能自己加锁自己释放。
- 重入性:同一个节点的同一个线程如果获得锁之后,它也可以再次获取这个锁。
案例
在这里插入代码片
问题1:单机版没加锁
解决:在单机环境下,可以使用synchronized或Lock来实现。
问题2:分布式部署后,单机锁还是出现超卖现象,需要分布式锁
解决:
问题3:出异常的话,可能无法释放锁,必须要在代码层面finally释放锁
问题4:服务器宕机了
部署了微服务jar包的机器挂了,代码层面根本没有走到finally这块,没办法保证解锁,这个key没有被删除,需要加入一个过期时间限定key
问题5:设置key+过期时间分开了,必须要合并成一行具备原子性
问题6:删除了别人的锁
问题7:finally块的判断+del删除操作不是原子性的
解决:用lua脚本
截止到这里,基于单个Redis节点实现分布式锁
问题8:确保redisLock过期时间大于业务执行时间的问题
Redis集群与zookeeper集群对比
- Redis 集群AP (互联网电商)
redis异步复制造成的锁丢失
比如:主节点没来的及把刚刚set进来这条数据给从节点,master就挂了,从机上位但从机上无该数据 - zookeeper 集群CP(金融)
综上:
redis集群环境下,我们自己写的也不OK,直接上RedLock之Redisson落地实现
下面基于多个Redis节点实现高可靠的分布式锁
解锁
单机案例
加锁关键逻辑
解锁关键逻辑
多机案例
基于setnx的分布式锁有什么缺点?
- 线程 1 首先获取锁成功,将键值对写入 redis 的 master 节点;
- 在 redis 将该键值对同步到 slave节点之前,master 发生了故障;
- redis 触发故障转移,其中一个 slave 升级为新的 master;
- 此时新的 master并不包含线程 1 写入的键值对,因此线程 2 尝试获取锁也可以成功拿到锁;
- 此时相当于有两个线程获取到了锁,可能会导致各种预期之外的情况发生,例如最常见的脏数据。
我们加的是排它独占锁,同一时间只能有一个建redis锁成功并持有锁,严禁出现2个以上的请求线程拿到锁。危险的
容错率公式:
N = 2X + 1 (N是最终部署机器数,X是容错机器数)