使用命令
set locks:some-resource-name 14527237283 NX PX 5000
当获得锁返回 1 未能获得 返回 0,其中 value 为随机值。
为什么使用 set 命令
setnx
很方便但是设计锁超时比较复杂。
为什么使用随机值作为 value
假设线程A获得锁超时为 3s
但是线程 A 未能在 3s 内完成业务,3s 后 redis 将 key 自动释放线程B获得锁,线程A在5s时并决定释放锁(如果不进行任何锁超时计算)调用 del locks:some-resource-name
此时会删除线程 B 的锁也就是异常释放了 线程B 的业务,但是线程 B 并没有完成。
如何解决这个问题?
将 value 设置为随机值,释放锁匹配key和value线程A和线程B在不同时间获得锁所以 value 必须是随机的才能避免误操作,同时释放锁的操作需要一个命令完成也就是需要原子操作,可以通过使用 lua 脚本完成原子操作, Redis 的命令处理是单线程的所以执行一段脚本保证原子操作。具体脚本内容如下:
KEYS[1] == locks:some-resource-name
ARGV[1] == 14527237283
if redis.call("get",KEYS[1]) == ARGV[1] then
return redis.call("del",KEYS[1])
else
return 0
end
注意:random_value 一定要保证唯一性
相关思考
关于锁超时过期,业务进行中的线程 A (服务A)无法感知锁已超时,线程 B (服务B)得到锁与线程A形成竞争,这种问题应该尽量控制锁过期时间大于业务时间如果业务时间过程不应该使用锁实现,业务允许可以通过队列实现。
网友评论