分散ロック] 03- [使用RedissonはRedLock原則を達成します

序文

すでに原則Redissionリエントラントロックと公正なロックを学習し、その後のRedLock Redissionを達成する方法を見て。

RedLock原理

RedLockが実装Redisの分散ロックに基づいており、それは次の機能を保証することができます。

  • 相互排他性:任意の時点で、1つのクライアントだけがロックを保持することができ、避けるのデッドロック:
  • クライアントがロックを取得する場合は、クライアントのダウンタイムやネットワークパーティションが発生した場合でも、それがデッドロックしません。(使用の重要な生存時間)
  • レジリエンス:として長い正常動作の大部分のノードRedisの例として、ロックサービスを提供したり、ロックを解除することが可能です。

RedLockアルゴリズムだけでなく、Redisの例のロックを作成し、複数のインスタンスのRedisロック上で作成しなければならないことを意味し、1 + 2 / n-は、成功したほとんどの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、例えば、我々は、分散ロック・ロック成功と見なさ成功したロックの後、少なくとも2つの例を3つのクライアントインスタンスを持っています。

その後、我々は見てlock()具体的な実現

原則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}

コアコードは、すべてのRedisのクライアントを通じて考えRedLockに基づいている非常に単純な原理を達成し、その後ロックをオンにする注記を追加した、成功回数の最後のカウントは、ロックが成功したかどうかを判断します。

宣言

:私のブログから始まるこの記事https://www.cnblogs.com/wang-mengと公共番号:ロマンチックみなさ一つramiflorous BEは、ソースを明記してください転載必要があります!

興味のパートナーは、個々の国民の少数心配することができる:一つの枝にはロマンチックな花を数えます

22.jpg

おすすめ

転載: www.cnblogs.com/wang-meng/p/12536660.html