redis 分布式讀寫鎖


http://zhangtielei.com/posts/blog-redlock-reasoning.html

鏈接里這篇 blog 討論了 redis 分布式鎖的實現以及安全性

 

我要參考 基於單Redis節點的分布式鎖,實現一個 基於單Redis節點的分布式讀寫鎖

 

先是想到一個不是很好的方案

read lock

eval "if not redis.call('GET', KEYS[1]) then return redis.call('SET', KEYS[2] .. '.' .. ARGV[1], ARGV[1], 'NX', 'PX', ARGV[2]) end" 2 rwlock.write rwlock.read unique_value 300000


write lock 分兩步,第一步 SET 成功且第二步返回空,則寫鎖成功。第二步等待所有的讀都解鎖,只是這個 KEYS 命令效率太低,所以說這不是一個好方案

SET rwlock.write unique_value NX PX 300000
KEYS rwlock.read.*


read unlock

DEL rwlock.read.unique_value


write unlock

eval "if redis.call('GET', KEYS[1]) == ARGV[1] then return redis.call('DEL', KEYS[1]) end" 1 rwlock.write unique_value

 

這個讀寫鎖有個好處,當有人等待可寫狀態時,不會再有新的人增加讀狀態的人數,所以不會有等到死也等不來可寫狀態的事情發生

 

好一點的讀寫鎖

參考 https://github.com/redisson/redisson/blob/master/redisson/src/main/java/org/redisson/RedissonReadLock.java

額外弄一個 hash table 存取讀的信息,避免用 KEYS 命令。大致步驟如下


read lock

eval
"if not redis.call('GET', KEYS[1]) then
redis.call('HSET', KEYS[2], ARGV[1], ARGV[2])
redis.call('SET', ARGV[1], ARGV[2], 'PX', ARGV[2])
local t = redis.call('PTTL', KEYS[2])
redis.call('PEXPIRE', KEYS[2], math.max(t, ARGV[2]))
end" 2 rwlock.write rwlock.read unique_value 300000

 

write lock

SET rwlock.write unique_value NX PX 300000
EXISTS rwlock.read  // 這里等待的時候應該不斷地更新 rwlock.write 的過期時間

 

read unlock

"if redis.call('HEXISTS', KEYS[1], KEYS[2]) == 0 then return end
redis.call('HDEL', KEYS[1], KEYS[2]);
local t1 = redis.call('PTTL', KEYS[1]);
local t2 = redis.call('PTTL', KEYS[2]);
redis.call('DEL', KEYS[2])
if t1 > t2 then return end
local maxRemainTime = -2
local keys = redis.call('HKEYS', KEYS[1]);
for k,v in pairs(keys) do
local remainTime = redis.call('PTTL', v)
maxRemainTime = math.max(maxRemainTime, remainTime)
end
if maxRemainTime > 0 then
redis.call('PEXPIRE', KEYS[1], maxRemainTime)
end" 2 rwlock.read unique_value


write unlock

eval "if redis.call('GET', KEYS[1]) == ARGV[1] then return redis.call('DEL', KEYS[1]) end" 1 rwlock.write unique_value

 

第二種如果要支持重復加鎖,只需稍微再改改

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM