3.分佈式紅鎖的leaseTime的設計原理
提前做2個動作:
1.先把3臺 redis key全部清空(爲了不受debug干擾,必須先刪除鎖)
127.0.0.1:6379> flushdb
OK
都設置爲30分鐘超時 過期
2.isLock = redLock.tryLock(10006030, 10006030, TimeUnit.MILLISECONDS);
leaseTime就是租約時間,就是redis key的過期時間。
long newLeaseTime = -1;
if (leaseTime != -1) {
if (waitTime == -1) {
newLeaseTime = unit.toMillis(leaseTime);
} else {
newLeaseTime = unit.toMillis(waitTime)*2;
}
}
爲什麼要新建一個newLeaseTime?而且還是unit.toMillis(waitTime)*2 ?? 關於這個newLeaseTime我思考了很久,花了我一個下午的時間才研究透!
1.先新建一個臨時的leasetime ,用(waitTime)*2
2.把臨時的leasetime設置到tryLockInnerAsync
redis.call('pexpire', KEYS[1], ARGV[1]);
臨時的LeaseTime
for循環執行完後tryLockInnerAsync 後,看下3臺redis實例,看下剩餘時間是多少,都是60分鐘
127.0.0.1:6379> ttl MY_REDLOCK
(integer) 3494
真實的LeaseTime
最後再重新設置真實的LeaseTime
if (leaseTime != -1) {
List<RFuture<Boolean>> futures = new ArrayList<>(acquiredLocks.size());
for (RLock rLock : acquiredLocks) {
RFuture<Boolean> future = ((RedissonLock) rLock).expireAsync(unit.toMillis(leaseTime), TimeUnit.MILLISECONDS);
futures.add(future);
}
for (RFuture<Boolean> rFuture : futures) {
rFuture.syncUninterruptibly();
}
}
127.0.0.1:6379> ttl MY_REDLOCK
(integer) 1665
總結:
這種設計的好處就是避免了前面代碼在執行過程中,損失了leasetime,導在leasetime精度丟失。
所以用了一個newLeaseTime先設置一個臨時的過期時間;
最後在結束的時候再重新設置了leasetime,保證代碼邏輯的嚴謹性,這種代碼的嚴謹性,真是值得我們去學習。
今後大家在寫過期時間的時候,如果複雜度高的話,建議在代碼的最後再重新設置過期時間,保證精度不丟失。