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
第二种如果要支持重复加锁,只需稍微再改改
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通