redis实现分布式锁(一)

119 阅读2分钟

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

使用SETNX + EXPIRE实现分布式锁

首先线程在争夺锁的时候,使用redis的setnx命令,因为redis是单线程, 能保证setnx同一个key时,可以成功执行的命令只有一个,也就是说,只有一个线程能获取锁,其他线程在执行setnx失败后,即陷入阻塞状态,或者自旋等待。

当抢到锁,线程执行逻辑,执行完之后删除key,进行锁释放,其他锁可恢复就绪状态,准备再执行setnx命令争抢锁。在此之下,当持有锁的线程发生了异常,或者宕机,就会造成锁无法释放的情况,此时其他线程就会永远无法得到锁。为了避免这种情况的发生,在setnx key时,同时指定一个过期时间,比如设置10s,就算此时线程发生异常无法释放锁,在10s之后,key会过期,锁就会自动释放。

setnx说明: 线程在执行SETNX时, 如果此时key不存在,则SETNX成功会返回1,如果这个key已经存在,则会返回0。

SETNX + 时间

在setnx + expire方案中,setnx和expire两个命令分开执行了,不是原子操作。非原子操作,那两个命令执行的间隔,必然会可能发生其他的事,比如如果执行完setnx,还没执行expire设置过期时间时,进程中断或者服务宕机,那么这个锁也会出现无法释放的情况,其他线程也就永远获取不到锁了。

此时SETNX + 时间的方式,就可以将setnx+expire命令合并,形成原子操作,可以达到相同的效果。

形成原子操作后,也就避免了在两条期间的间隔期间发生其他的事。

这个时间,可以是指定系统时间,也可以指定过期时间,但此时会要求在多服务高可用部署下,每个服务器的系统时间要求是同步的。