在redis文档中,我发现可以通过SETNX实现原始锁:
http://redis.io/commands/setnx
C4发送SETNX lock.foo以获取锁
崩溃的客户端C3仍然保留它,因此Redis将回复0到C4.
C4发送GET lock.foo来检查锁是否过期.如果不是,它会睡一段时间并从头开始重试.
相反,如果锁定已到期,因为lock.foo上的Unix时间早于当前的Unix时间,C4会尝试执行:
GETSET lock.foo
由于GETSET语义,C4可以检查存储在key中的旧值是否仍然是过期时间戳.如果是,则获得锁定.
如果另一个客户端(例如C5)比C4快并且通过GETSET操作获得锁定,则C4 GETSET操作将返回未过期的时间戳.C4将从第一步开始重新启动.请注意,即使C4将来设置密钥几秒钟,这也不是问题.
但是,正如一些用户所评论的那样,使用UNIX时间戳作为过期时间需要客户端和服务器的时间完全同步.有没有更好的替代方法在Redis中创建全局/分布式锁?
使用redis> = 2.6,LUA脚本解决方案会很棒.Lua脚本总是原子地执行所以:
--lockscript, parameters: lock_key, lock_timeout local lock = redis.call('get', KEYS[1]) if not lock then return redis.call('setex', KEYS[1], ARGV[1], "locked"); end return false
另一种基于新SET
命令选项的解决方案
SET lock_key "locked" EX lock_timeout NX
使用redis <2.6可以使用带有multi的模式:
MULTI SETNX tmp_unique_lock some_value EXPIRE tmp_unique_lock RENAMENX tmp_unique_lock real_lock EXEC
用SET
而不是SETNX
.SET
接受过期时间的参数,以秒和毫秒为单位,而不是UNIX时间戳值.
仅基于历史原因记录旧的基于SETNX的模式.
来自SETNX
描述:
注意:从Redis 2.6.12开始,可以使用SET命令创建更简单的锁定原语来获取锁,并使用简单的Lua脚本来释放锁.该模式记录在SET命令页面中.