【分布式锁】03-使用Redisson实现RedLock原理

前面已经学习了Redission可重入锁以及公平锁的原理,接着看看Redission是如何来实现RedLock的。

RedLock原理

RedLock是基于redis实现的分布式锁,它能够保证以下特性:

互斥性:在任何时候,只能有一个客户端能够持有锁;避免死锁:

当客户端拿到锁后,即使发生了网络分区或者客户端宕机,也不会发生死锁;(利用key的存活时间)

容错性:只要多数节点的redis实例正常运行,就能够对外提供服务,加锁或者释放锁;

RedLock算法思想,意思是不能只在一个redis实例上创建锁,应该是在多个redis实例上创建锁,n / 2 + 1,必须在大多数redis节点上都成功创建锁,才能算这个整体的RedLock加锁成功,避免说仅仅在一个redis实例上加锁而带来的问题。

这里附上一个前几天对RedLock解析比较透彻的文章:
https://mp.weixin.qq.com/s/gOYWLg3xYt4OhS46woN_Lg

Redisson实现原理

Redisson中有一个MultiLock的概念,可以将多个锁合并为一个大锁,对一个大锁进行统一的申请加锁以及释放锁

而Redisson中实现RedLock就是基于MultiLock 去做的,接下来就具体看看对应的实现吧

RedLock使用案例

先看下官方的代码使用:
(https://github.com/redisson/redisson/wiki/8.-distributed-locks-and-synchronizers#84-redlock)

1RLock lock1 = redisson1.getLock("lock1");
2RLock lock2 = redisson2.getLock("lock2");
3RLock lock3 = redisson3.getLock("lock3");
4
5RLock redLock = anyRedisson.getRedLock(lock1, lock2, lock3);
6
7// traditional lock method
8redLock.lock();
9
10// or acquire lock and automatically unlock it after 10 seconds
11redLock.lock(10, TimeUnit.SECONDS);
12
13// or wait for lock aquisition up to 100 seconds 
14// and automatically unlock it after 10 seconds
15boolean res = redLock.tryLock(100, 10, TimeUnit.SECONDS);
16if (res) {
17   try {
18     ...
19   } finally {
20       redLock.unlock();
21   }
22}

这里是分别对3个redis实例加锁,然后获取一个最后的加锁结果。

RedissonRedLock实现原理

上面示例中使用redLock.lock()或者tryLock()最终都是执行RedissonRedLock中方法。

RedissonRedLock 继承自RedissonMultiLock, 实现了其中的一些方法:

1public class RedissonRedLock extends RedissonMultiLock {
2    public RedissonRedLock(RLock... locks) {
3        super(locks);
4    }
5
6    /**
7     * 锁可以失败的次数,锁的数量-锁成功客户端最小的数量
8     */
9    @Override
10    protected int failedLocksLimit() {
11        return locks.size() - minLocksAmount(locks);
12    }
13
14    /**
15     * 锁的数量 / 2 + 1,例如有3个客户端加锁,那么最少需要2个客户端加锁成功
16     */
17    protected int minLocksAmount(final List<RLock> locks) {
18        return locks.size()/2 + 1;
19    }
20
21    /** 
22     * 计算多个客户端一起加锁的超时时间,每个客户端的等待时间
23     * remainTime默认为4.5s
24     */
25    @Override
26    protected long calcLockWaitTime(long remainTime) {
27        return Math.max(remainTime / locks.size(), 1);
28    }
29
30    @Override
31    public void unlock() {
32        unlockInner(locks);
33    }
34
35}

看到locks.size()/2 + 1 ,例如我们有3个客户端实例,那么最少2个实例加锁成功才算分布式锁加锁成功。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zgfjxx.html