1. 程式人生 > 其它 >Redisson解決redis分散式鎖過期業務沒執行完問題

Redisson解決redis分散式鎖過期業務沒執行完問題

Redisson
Redisson是一個在Redis的基礎上實現的Java駐記憶體資料網格(In-Memory Data Grid)。

Redisson不僅提供了一系列的分散式的Java常用物件,還提供了許多分散式服務。其中包括(BitSet, Set, Multimap, SortedSet, Map, List, Queue, BlockingQueue, Deque, BlockingDeque, Semaphore, Lock, AtomicLong, CountDownLatch, Publish / Subscribe, Bloom filter, Remote service, Spring cache, Executor service, Live Object service, Scheduler service), Redisson提供了使用Redis的最簡單和最便捷的方法。

Redisson的宗旨是促進使用者對Redis的關注分離(Separation of Concern),從而讓使用者能夠將精力更集中地放在處理業務邏輯上。

lua程式碼實現
通過封裝在lua指令碼中傳送給redis,保證這段複雜業務邏輯執行的原子性。

加鎖
if (redis.call('exists', KEYS[1]) == 0) then
redis.call('hset', KEYS[1], ARGV[2], 1);
redis.call('pexpire', KEYS[1], ARGV[1]);
return nil;
end;
if (redis.call('hexists', KEYS[1], ARGV[2]) == 1) then
redis.call('hincrby', KEYS[1], ARGV[2], 1);
redis.call('pexpire', KEYS[1], ARGV[1]);
return nil;
end;
return redis.call('pttl', KEYS[1]);
釋放鎖
if (redis.call('exists', KEYS[1]) == 0) then
redis.call('publish', KEYS[2], ARGV[1]);
return 1;
end;
if (redis.call('hexists', KEYS[1], ARGV[3]) == 0) then
return nil;
end;
local counter = redis.call('hincrby', KEYS[1], ARGV[3], -1);
if (counter > 0) then
redis.call('pexpire', KEYS[1], ARGV[2]);
return 0;
else redis.call('del', KEYS[1]);
redis.call('publish', KEYS[2], ARGV[1]);
return 1;
end;
return nil;
Redisson實現分散式鎖
可重入鎖
RLock lock = redisson.getLock("lock");
lock.lock();

lock.unlock()

// 加鎖以後10秒鐘自動解鎖
// 無需呼叫unlock方法手動解鎖
lock.lock(10, TimeUnit.SECONDS);

// 嘗試加鎖,最多等待100秒,上鎖以後10秒自動解鎖
boolean res = lock.tryLock(100, 10, TimeUnit.SECONDS);
...
lock.unlock();
公平鎖
RLock fairLock = redisson.getFairLock("anyLock");
// 最常見的使用方法
fairLock.lock();

// 10秒鐘以後自動解鎖
// 無需呼叫unlock方法手動解鎖
fairLock.lock(10, TimeUnit.SECONDS);

// 嘗試加鎖,最多等待100秒,上鎖以後10秒自動解鎖
boolean res = fairLock.tryLock(100, 10, TimeUnit.SECONDS);
...
fairLock.unlock();
watch dog自動延期機制
Redisson中客戶端一旦加鎖成功,就會啟動一個watch dog看門狗。watch dog是一個後臺執行緒,會每隔10秒檢查一下,如果客戶端還持有鎖key,那麼就會不斷的延長鎖key的生存時間。

如果負責儲存這個分散式鎖的Redission節點宕機後,而且這個鎖正好處於鎖住的狀態時,這個鎖會出現鎖死的狀態,為了避免這種情況的發生,Redisson提供了一個監控鎖的看門狗,它的作用是在Redisson例項被關閉前,不斷的延長鎖的有效期。預設情況下,看門狗的續期時間是30s,也可以通過修改Config.lockWatchdogTimeout來另行指定。

另外Redisson 還提供了可以指定leaseTime引數的加鎖方法來指定加鎖的時間。超過這個時間後鎖便自動解開了,不會延長鎖的有效期。

缺點
對某個redis master例項,寫入了myLock這種鎖key的value,此時會非同步複製給對應的master slave例項。但是這個過程中一旦發生redis master宕機,主備切換,redis slave變為了redis master。就會導致客戶端2來嘗試加鎖的時候,在新的redis master上完成了加鎖,而客戶端1也以為自己成功加了鎖。

此時就會導致多個客戶端對一個分散式鎖完成了加鎖。這時系統在業務上一定會出現問題,導致髒資料的產生。所以這個就是redis cluster,或者是redis master-slave架構的主從非同步複製導致的redis分散式鎖的最大缺陷:在redis master例項宕機的時候,可能導致多個客戶端同時完成加鎖。