redis 实现分布式锁(二)
使用 Lua 脚本
简单说一下 Lua 脚本的特点:首先 Lua 是一种轻量的脚本语言,用标准语言编写,并于源代码形式开放,非常适合嵌入别的程序里、Lua 也提供了非常易于使用的扩展接口和机制、支持面向过程编程和函数式编程、自动内存管理等。
在全面提到,使用命令 SETNX + EXPIRE 实现分布式锁的方案中,是由于两个操作不是原子操作,会导致分布式锁无法实现的原因。
要保证原子性,还有一种方式可以实现,就是使用 Lua 脚本,
SET 的扩展命令(SET EX PX NX)
除了使用 Lua 脚本保证 SETNX + EXPIRE 两条指令的原子性,还可以使用 Redis 的 SET 指令扩展参数:SET key value EX|PX NX|XX,这也是具有原子性的。
参数解释:
其中的 EX,指的是 key 的过期时间
PX 和 EX 一样,指的过期时间,只是单位不一样,PX 是毫秒,EX 是秒。
NX 表示在指定 key 不存在时,才能成功执行命令
XX 和 NX 相反,是指定 key 存在时,才会成功执行命令,不然会失败
SET EX|PX NX|XX + 唯一 value 值(UUID)
SET 的扩展命令(SET EX PX NX)方式的缺点:
存在一种情况:指定的 key 已经过期了,但是线程还没执行完逻辑,到期锁就自动释放,此时别的锁开始争抢锁并执行逻辑,这会使程序混乱。
在设置 key 时,没有规定只能设置的线程去释放,只要指定的 key 值,其他线程可以直接对 key 进行删除。
解决方案:设置 key 时,线程生成一个随即不重复的数,比如生成 UUID,然后临时保存起来。删除 key 时,校验 key 中保存的 value 是否是当前线程临时保存的 UUID,如果不是,则无法删除锁,只要是的情况下才能删除 key 释放锁。
版权声明: 本文为 InfoQ 作者【zarmnosaj】的原创文章。
原文链接:【http://xie.infoq.cn/article/2fa27f545f6cc86032023f165】。
本文遵守【CC-BY 4.0】协议,转载请保留原文出处及本版权声明。
评论