Redis分散式鎖
應用場景:
當多個應用程序(客戶端)需要互斥地訪問共享資源時,可以使用分散式鎖。其中Redis官方權威提出了RedLock。Java中可使用Redssion提供的實現。
注意點:
- 互斥,保證任何時刻只能有一個客戶端 獲取到鎖;
- 效率之死鎖,保證獲取到鎖的客戶端即使在出現網路分割槽或者宕機的情況下,也能釋放掉鎖;
- 效率之容錯,保證只要大多數Redis節點正常工作,客戶端就能正常獲取到鎖和正常釋放鎖。
原理:
獲取鎖:
SET resource_name my_random_value NX [EX|PX] 30000
Redssion中的實現使用了Hash,可重入:
if (redis.call(‘exists’,KEYS[1]) == 0)
then redis.call(‘hset’,KEYS[1],ARGV[2],1);
redis.call(‘pexpire’,ARGV[1]);
return nil;
end;
if (redis.call(‘hexists’,ARGV[2]) == 1)
then redis.call(‘hincrby’,1);
redis.call(‘pexpire’,ARGV[1]);
return nil;
end;
return redis.call(‘pttl’,KEYS[1]);
釋放鎖:
if redis.call(“get”,KEYS[1]) == ARGV[1] then
return redis.call(“del”,KEYS[1])else
return 0
end
Redisson的釋放鎖實現:
if (redis.call(‘hexists’,ARGV[3]) == 0)
then return nil;
end;
local counter = redis.call(‘hincrby’,ARGV[3],
-1);
if (counter > 0)
then redis.call(‘pexpire’,ARGV[2]);
return 0;
else redis.call(‘del’,KEYS[1]);
redis.call(‘publish’,KEYS[2],ARGV[1]);return 1;
end;
return nil;
Redis分佈鎖常見的幾種實現方案:
-
單機
缺點:單點故障,整個服務無法使用。 -
主從複製
缺點:failover問題。 根本原因在於主從複製有延遲。當master在slave複製成功前宕機,slave晉升為master時沒有宕機時的鎖資訊,導致有可能出現兩個客戶端同時持有同一把鎖。
舉例:
a. client A 在master拿到鎖
b. master節點把A建立的鎖資訊同步到slave之前宕機了
c. slave晉升為master節點
d. client B 在新master拿到與A相同的鎖(此時A以為自己仍持有鎖)
…TODO
Redisson使用DEMO程式碼片段:
使用Redisson加鎖 釋放鎖業務程式碼