什么是redLock
RedLock算法思想,不只在一个redis实例上创建锁,是在多个redis实例上创建锁,n / 2 + 1,必须在大多数redis节点上都成功创建锁,才能算这个整体的RedLock加锁成功,避免说仅仅在一个redis实例上加锁。
普通的redis分布式锁,其实是在redis集群中根据hash算法选择一台redis实例创建一个锁就可以了
大致流程如下:
- 获取当前时间戳,单位是毫秒
- 跟上面类似,轮流尝试在每个master节点上创建锁,过期时间较短,一般就几十毫秒,在每个节点上创建锁的过程中,需要加一个超时时间,一般来说比如几十毫秒如果没有获取到锁就超时了,标识为获取锁失败
- 尝试在大多数节点上建立一个锁,比如3个节点就要求是2个节点(n / 2 +1)
- 客户端计算建立好锁的时间,如果建立锁的时间小于超时时间,就算建立成功了
- 要是锁建立失败了,那么就依次删除已经创建的锁
- 只要别人创建了一把分布式锁,你就得不断轮询去尝试获取锁
实现
RLock lock1 = redisson.getLock("anyLock1");
RLock lock2 = redisson.getLock("anyLock2");
RLock lock3 = redisson.getLock("anyLock3");
RedissonRedLock redissonRedLock = new RedissonRedLock(lock1, lock2, lock3);
redissonRedLock.lock();
redissonRedLock.unlock();
剖析
RedissonRedLock锁的实现,非常的简单,他是RedissonMultiLock的一个子类,RedLock算法的实现,是依赖于MultiLock的一个机制来实现的
主要就是通过方法的重写,改变了MultiLock中的几个特殊的行为
failedLocksLimit,locks.size() - minLocksAmount(locks) = 1,也就是failedLocksLimit,就是能够加锁失败的一个数量
minLocksAmount(locks)里面就是用的大多数节点的一个算法,n / 2 + 1,比如你有3个lock,那么至少要成功加上3 / 2 + 1 = 2个lock
RedLock里包裹了3个小锁,最多能够加锁失败1个锁
calcLockWaitTime,这个东西算出来的时间,是说在对每个lock进行加锁的时候,有一个尝试获取锁超时的时间,原来默认的就是remainTime,4500毫秒,4500毫秒 / 3 = 1500毫秒,每个小lock获取锁超时的时间改成了1500毫秒
waitTime = 4500毫秒
remainTime = 4500毫秒
lockWaitTIme = 1500毫秒
failedLocksLimit,默认是0,就是一个锁都不能容忍加失败了,现在最新的是n - (n / 2 + 1),3个lock,最多可以容忍1个lock加锁失败
waitTime = 1500毫秒
对每个小lock尝试加锁的时候,能够容忍的最大超时时间,就是1500毫秒,1500毫秒之内必须加成功这个小锁,否则就是加锁失败
大家先试想一下,如果是之前讲解的那个最原始的MultiLock,如果任何一个lock加锁失败了,走这里会如何呢?failedLocksLimit = 0,不可能的,因为你都已经一个锁加锁失败了,所以此处不可能等于0
如果failedLocksLimit是0,默认的一个行为,此时就会将所有已经加锁的lock都释放掉,返回一个false,标记本次尝试加锁失败
之前讲解的那个MultiLock的话,只要你有任何一个锁加锁失败,此次加这个MultiLock就会标记为失败,再重来一次
但是,现在的话呢,使用的是RedLock,faildLocksLimit(3个小lock的时候,这个值是1),可以容忍一个锁加锁失败的,此时就会将failedLockLimit–,从1变为了0,也就是说之前可以容忍一次lock加锁失败,但是此时已经失败了一次了,不能再容忍加锁失败了
如果第二个lock加锁又失败了,此时failedLocksLimit已经是0了,那么就会标记为加锁失败,RedLock加锁失败了
如果是假设是3个lock,前2个加锁成功的,最后一个加锁失败了,3 - 2 = 1 = failedLocksLimit,此时是正好需要的最少的加锁的次数都加锁成功了,剩余的锁加锁失败了,也不要紧的,本次加锁就成功了
也就是说,针对多个lock进行加锁,每个lock都有一个1500毫秒的加锁超时时间,如果在4500毫秒内,成功的对n / 2 + 1个lock加锁成功了,就可以认为这个RedLock加锁成功了,不要求所有的lock都加锁成功的
RedLock,是一个锁,只不过是在各个不同的master实例上进行加锁,但是现在说RedLock合并了多个小lock。也就是说,如果你有3个redis master实例,你就用lock1、lock2、lock3三个锁key,人家本来就是分布在3个不同的redis master实例上的
加这个RedLock,相当于是3个redis master实例上的key,有2个加成功了,就算这个RedLock加锁成功了
此时别人如果要来加锁,用一样的key,人家是无法成功加锁的,锁被你占用了,人家就会卡在那儿,死循环,不断的尝试加锁,直到你释放锁