分散式鎖原始碼剖析(3) Redisson的MultiLock和RedLock
阿新 • • 發佈:2018-12-27
MultiLock
MultiLock:將多個鎖合併為一個大鎖,對一個大鎖進行統一的申請加鎖以及釋放鎖,一次性鎖定多個資源,再去處理一些事情,然後事後一次性釋放所有的資源對應的鎖。
maven配置檔案:
<dependency> <groupId>org.redisson</groupId> <artifactId>redisson</artifactId> <version>3.8.1</version> </dependency>
程式碼示例:
Config config = new Config(); Config config = new Config(); config.useClusterServers() .addNodeAddress("redis://192.168.31.114:7001") .addNodeAddress("redis://192.168.31.184:7002"); RedissonClient redisson = Redisson.create(config); RLock lock1 = redisson.getLock("lock1"); RLock lock2 = redisson.getLock("lock2"); RLock lock3 = redisson.getLock("lock3"); RedissonMultiLock lock = new RedissonMultiLock(lock1, lock2, lock3); // locks: lock1 lock2 lock3 lock.lock(); lock.unlock();
核心原始碼:
根據鎖的個數,計算出基礎的等待時間。
long baseWaitTime = locks.size() * 1500;
迴圈嘗試獲取鎖,直到獲取鎖成功後返回。
while (true) {
if (tryLock(waitTime, leaseTime, unit)) {
return;
}
}
呼叫RedissonLock的tryLock方法,嘗試獲取鎖,如果獲取鎖成功,把鎖新增到集合。
List<RLock> acquiredLocks = new ArrayList<RLock>(locks.size()); lockAcquired = lock.tryLock(); acquiredLocks.add(lock);
如果獲取鎖超時就會退出,重新再次死迴圈嘗試獲取鎖。
if (locks.size() - acquiredLocks.size() == failedLocksLimit()) {
break;
}
if (failedLocksLimit == 0) {
unlockInner(acquiredLocks);
if (waitTime == -1 && leaseTime == -1) {
return false;
}
failedLocksLimit = failedLocksLimit();
acquiredLocks.clear();
// reset iterator
while (iterator.hasPrevious()) {
iterator.previous();
}
} else {
failedLocksLimit--;
}
RedLock
maven配置檔案:
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson</artifactId>
<version>3.8.1</version>
</dependency>
程式碼示例:
Config config = new Config();
config.useClusterServers()
.addNodeAddress("redis://192.168.31.114:7001")
.addNodeAddress("redis://192.168.31.184:7002");
RedissonClient redisson = Redisson.create(config);
RLock lock1 = redisson.getLock("lock1");
RLock lock2 = redisson.getLock("lock2");
RLock lock3 = redisson.getLock("lock3");
RedissonRedLock lock = new RedissonRedLock(lock1, lock2, lock3);
// locks: lock1 lock2 lock3
lock.lock();
lock.unlock();
演算法原理:
1、獲取當前時間戳,單位是毫秒。
2、跟上面類似,輪流嘗試在每個master節點上建立鎖,過期時間較短,一般就幾十毫秒,在每個節點上建立鎖的過程中,需要加一個超時時間,一般來說比如幾十毫秒如果沒有獲取到鎖就超時了,標識為獲取鎖失敗。
3、嘗試在大多數節點上建立一個鎖,比如3個節點就要求是2個節點(n / 2 +1)。
4、客戶端計算建立好鎖的時間,如果建立鎖的時間小於超時時間,就算建立成功了。
5、要是鎖建立失敗了,那麼就依次刪除已經建立的鎖。
6、只要別人建立了一把分散式鎖,你就得不斷輪詢去嘗試獲取鎖。
核心原始碼:
是RedissonMultiLock的一個子類,RedLock演算法的實現,是依賴於MultiLock的一個機制來實現。主要通過重寫failedLocksLimit和calcLockWaitTime實現,只有n/2+1個加鎖操作失敗之後,才會重新去迴圈加鎖。
public class RedissonRedLock extends RedissonMultiLock {
public RedissonRedLock(RLock... locks) {
super(locks);
}
@Override
protected int failedLocksLimit() {
return locks.size() - minLocksAmount(locks);
}
protected int minLocksAmount(final List<RLock> locks) {
return locks.size()/2 + 1;
}
@Override
protected long calcLockWaitTime(long remainTime) {
return Math.max(remainTime / locks.size(), 1);
}
@Override
public void unlock() {
unlockInner(locks);
}
}