redis实现分布式锁(二)

137 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第26天,点击查看活动详情

使用Lua脚本

简单说一下Lua脚本的特点: 首先Lua是一种轻量的脚本语言,用标准语言编写,并于源代码形式开放,非常适合嵌入别的程序里、Lua也提供了非常易于使用的扩展接口和机制、支持面向过程编程和函数式编程、自动内存管理等。

在全面提到,使用命令SETNX + EXPIRE实现分布式锁的方案中,是由于两个操作不是原子操作,会导致分布式锁无法实现的原因。

要保证原子性,还有一种方式可以实现,就是使用Lua脚本,

SET的扩展命令(SET EX PX NX)

除了使用Lua脚本保证SETNX + EXPIRE两条指令的原子性,还可以使用Redis的SET指令扩展参数:SET key value EX|PX NX|XX,这也是具有原子性的。

参数解释:

  1. 其中的EX,指的是key的过期时间
  2. PX和EX一样,指的过期时间,只是单位不一样,PX是毫秒,EX是秒。
  3. NX表示在指定key不存在时,才能成功执行命令
  4. XX和NX相反,是指定key存在时,才会成功执行命令,不然会失败

SET EX|PX NX|XX + 唯一value值(UUID)

SET的扩展命令(SET EX PX NX)方式的缺点:

  1. 存在一种情况:指定的key已经过期了,但是线程还没执行完逻辑,到期锁就自动释放,此时别的锁开始争抢锁并执行逻辑,这会使程序混乱。
  2. 在设置key时,没有规定只能设置的线程去释放,只要指定的key值,其他线程可以直接对key进行删除。

解决方案: 设置key时,线程生成一个随即不重复的数,比如生成UUID,然后临时保存起来。 删除key时,校验key中保存的value是否是当前线程临时保存的UUID,如果不是,则无法删除锁,只要是的情况下才能删除key释放锁。