参考:
1,Redisson 实现 Redis 分布式锁的 N 种姿势
2,Redlock:Redis 分布式锁最牛逼的实现
3,Redis 全面解析三:redis 分布式锁的实现原理你了解吗
4,Redis 分布式锁的底层原理
推荐参考:Redis 中是如何实现分布式锁的?
Redisson 这个框架对 Redis 分布式锁的实现原理图如下:
redis 分布式锁 是一个 渐进的过程 首先 setnx 这个命令 之后要被淘汰了,现在平时说的 setnx 指的是 set key value px milliseconds nx 这个命令 这个是原子的,但是只要这一个命令是不行的,在解锁的时候 不是原子的,需要借助 lua 脚本,即 eval 命令执行 lua 脚本。这时就可以引入 redssion 了,redssion 有两种锁实现。
加锁:set key value px milliseconds nx,这个命令 这个是原子的;
解锁:需要借助 lua 脚本,即 eval 命令执行 lua 脚本
value 要具有唯一性,释放锁时要验证 value 值,不能误解锁;
事实上这类琐最大的缺点就是它加锁时只作用在一个 Redis 节点上,即使 Redis 通过 sentinel 保证高可用,如果这个 master 节点由于某些原因发生了主从切换,那么就会出现锁丢失的情况:
在 Redis 的 master 节点上拿到了锁;
但是这个加锁的 key 还没有同步到 slave 节点;
master 故障,发生故障转移,slave 节点升级为 master 节点;
导致锁丢失。
这时 就引出 redission 基于 redlock 算法,redisson redlock 就解决了这个问题;它的不足是需要额外引入一套 redis 节点 满足多节点加锁的特性
在 Redis 的分布式环境中,我们假设有 N 个 Redis master。这些节点完全互相独立,不存在主从复制或者其他集群协调机制。我们确保将在 N 个实例上使用与在 Redis 单实例下相同方法获取和释放锁。现在我们假设有 5 个 Redis master 节点,同时我们需要在 5 台服务器上面运行这些 Redis 实例,这样保证他们不会同时都宕掉。
为了取到锁,客户端应该执行以下操作:
获取当前 Unix 时间,以毫秒为单位。
依次尝试从 5 个实例,使用相同的 key 和具有唯一性的 value(例如 UUID)获取锁。当向 Redis 请求获取锁时,客户端应该设置一个网络连接和响应超时时间,这个超时时间应该小于锁的失效时间。例如你的锁自动失效时间为 10 秒,则超时时间应该在 5-50 毫秒之间。这样可以避免服务器端 Redis 已经挂掉的情况下,客户端还在死死地等待响应结果。如果服务器端没有在规定时间内响应,客户端应该尽快尝试去另外一个 Redis 实例请求获取锁。
客户端使用当前时间减去开始获取锁时间(步骤 1 记录的时间)就得到获取锁使用的时间。当且仅当从大多数(N/2+1,这里是 3 个节点)的 Redis 节点都取到锁,并且使用的时间小于锁超时时间时,锁才算获取成功。
如果取到了锁,key 的真正有效时间等于有效时间减去获取锁所使用的时间(步骤 3 计算的结果)。
如果因为某些原因,获取锁失败(没有在至少 N/2+1 个 Redis 实例取到锁或者取锁时间已经超过了有效时间),客户端应该在所有的 Redis 实例上进行解锁(即便某些 Redis 实例根本就没有加锁成功,防止某些节点获取到锁但是客户端没有得到响应而导致接下来的一段时间不能被重新获取锁)。