Distributed Lock] 03- [use Redisson achieve RedLock principle

Foreword

As already learning the principles Redission reentrant locks and fair locks, and then look at how to achieve RedLock Redission of.

RedLock principle

RedLock is based on distributed lock redis implemented, it can guarantee the following features:

  • Mutual exclusivity: At any time, only one client can hold a lock; avoid deadlock:
  • When the client to get the lock, even if the client downtime or network partition occurred, it does not deadlock; (key survival time of use)
  • Resilience: As long as a majority node redis example of normal operation, it is possible to provide services, lock or release the lock;

RedLock algorithm, meaning that not only creates a lock on a redis example, should be created on multiple instances redis lock, the n-/ 2 + 1 , must have successfully created a lock on most redis nodes, this can be considered a whole RedLock lock success, to avoid problems, said only lock in on a redis instance brought.

RedLock here a few days to resolve attach a more thorough article ago:
https://mp.weixin.qq.com/s/gOYWLg3xYt4OhS46woN_Lg

The principle Redisson

Redisson there is a MultiLockconcept of multiple locks can be combined into one big lock, big lock on a unified application for locking and releasing the lock

The Redisson is based on the realization RedLock MultiLockdo, then we look at the specific corresponding implementation of it

RedLock use cases

Look at the official code uses:
( 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}

Here are examples of three redis lock, the lock then obtain a final result.

The principle RedissonRedLock

The example above using redLock.lock () or tryLock () ultimately perform RedissonRedLocka method.

RedissonRedLockInherited from RedissonMultiLock, implements some of these methods:

 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}

See locks.size()/2 + 1, for example, we have three client instances, then at least two examples of the successful locking considered distributed lock lock success.

Then we look at lock()the concrete realization

The principle RedissonMultiLock

  1public class RedissonMultiLock implements Lock {
2
3    final List<RLock> locks = new ArrayList<RLock>();
4
5    public RedissonMultiLock(RLock... locks) {
6        if (locks.length == 0) {
7            throw new IllegalArgumentException("Lock objects are not defined");
8        }
9        this.locks.addAll(Arrays.asList(locks));
10    }
11
12    public boolean tryLock(long waitTime, long leaseTime, TimeUnit unit) throws InterruptedException {
13        long newLeaseTime = -1;
14        if (leaseTime != -1) {
15            // 如果等待时间设置了,那么将等待时间 * 2
16            newLeaseTime = unit.toMillis(waitTime)*2;
17        }
18
19        // time为当前时间戳
20        long time = System.currentTimeMillis();
21        long remainTime = -1;
22        if (waitTime != -1) {
23            remainTime = unit.toMillis(waitTime);
24        }
25        // 计算锁的等待时间,RedLock中:如果remainTime=-1,那么lockWaitTime为1
26        long lockWaitTime = calcLockWaitTime(remainTime);
27
28        // RedLock中failedLocksLimit即为n/2 + 1
29        int failedLocksLimit = failedLocksLimit();
30        List<RLock> acquiredLocks = new ArrayList<RLock>(locks.size());
31        // 循环每个redis客户端,去获取锁
32        for (ListIterator<RLock> iterator = locks.listIterator(); iterator.hasNext();) {
33            RLock lock = iterator.next();
34            boolean lockAcquired;
35            try {
36                // 调用tryLock方法去获取锁,如果获取锁成功,则lockAcquired=true
37                if (waitTime == -1 && leaseTime == -1) {
38                    lockAcquired = lock.tryLock();
39                } else {
40                    long awaitTime = Math.min(lockWaitTime, remainTime);
41                    lockAcquired = lock.tryLock(awaitTime, newLeaseTime, TimeUnit.MILLISECONDS);
42                }
43            } catch (Exception e) {
44                lockAcquired = false;
45            }
46
47            // 如果获取锁成功,将锁加入到list集合中
48            if (lockAcquired) {
49                acquiredLocks.add(lock);
50            } else {
51                // 如果获取锁失败,判断失败次数是否等于失败的限制次数
52                // 比如,3个redis客户端,最多只能失败1次
53                // 这里locks.size = 3, 3-x=1,说明只要成功了2次就可以直接break掉循环
54                if (locks.size() - acquiredLocks.size() == failedLocksLimit()) {
55                    break;
56                }
57
58                // 如果最大失败次数等于0
59                if (failedLocksLimit == 0) {
60                    // 释放所有的锁,RedLock加锁失败
61                    unlockInner(acquiredLocks);
62                    if (waitTime == -1 && leaseTime == -1) {
63                        return false;
64                    }
65                    failedLocksLimit = failedLocksLimit();
66                    acquiredLocks.clear();
67                    // 重置迭代器 重试再次获取锁
68                    while (iterator.hasPrevious()) {
69                        iterator.previous();
70                    }
71                } else {
72                    // 失败的限制次数减一
73                    // 比如3个redis实例,最大的限制次数是1,如果遍历第一个redis实例,失败了,那么failedLocksLimit会减成0
74                    // 如果failedLocksLimit就会走上面的if逻辑,释放所有的锁,然后返回false
75                    failedLocksLimit--;
76                }
77            }
78
79            if (remainTime != -1) {
80                remainTime -= (System.currentTimeMillis() - time);
81                time = System.currentTimeMillis();
82                if (remainTime <= 0) {
83                    unlockInner(acquiredLocks);
84                    return false;
85                }
86            }
87        }
88
89        if (leaseTime != -1) {
90            List<RFuture<Boolean>> futures = new ArrayList<RFuture<Boolean>>(acquiredLocks.size());
91            for (RLock rLock : acquiredLocks) {
92                RFuture<Boolean> future = rLock.expireAsync(unit.toMillis(leaseTime), TimeUnit.MILLISECONDS);
93                futures.add(future);
94            }
95
96            for (RFuture<Boolean> rFuture : futures) {
97                rFuture.syncUninterruptibly();
98            }
99        }
100
101        return true;
102    }
103}

The core code has added a note to achieve the principle is very simple, based on RedLock thought through all the Redis client, and then turn the lock, the last count of the number of successes to determine whether the lock is successful.

Declare

This article starting from my blog: https://www.cnblogs.com/wang-meng and public numbers: One ramiflorous be considered romantic , should reprint please indicate the source!

Interested partner may be concerned about the small number of individual public: One branch count romantic flowers

22.jpg

Guess you like

Origin www.cnblogs.com/wang-meng/p/12536660.html