关于分布式锁,相信大家都用的非常普遍。分布式锁其实就是控制分布式系统间不同的服务,不同的进程或者不同的线程共享同一资源的一种方式。当共享资源被竞争,我们需要通过互斥来防止彼此干扰从而保证一致性,这个时候我们就需要使用分布式锁。
这篇文章我主要分享通过redis来实现分布式锁的方式,以及存在的问题。
setnx命令
set if not exists
设置一个值,或者填一个坑,设置完了或者填完了就没有了,只有del才能释放。
线上案例分享:
我们线上分布式锁就是使用的setnx,有一次因为线上问题,我们强制重启了一个服务,造成后面重启之后a数据一直没拿到。a数据只能让某一个服务能拿到。这个获取就是通过setnx实现的,因为a数据只能启动后一个服务获取到。后面查了许久才明白过来setnx执行之后,del没有执行成功,造成陷入死锁。像这种问题我们如何避免呢?是不是加个过期时间才能解决?其实过期时间也是会存在同样的问题,如果setnx成功,但是expire执行失败了,那还是同样会有问题。
总结案例:
使用setnx来控制并发,del或者expire的使用能一定程度上解决死锁的问题,但是如果两个命令有一个执行失败,那死锁就来了,就出现问题了。我们看到使用setnx存在的问题,我们想只有保证setnx和del或者setnx和expire原子性操作才能保证一定不会死锁。setnx和del是无法做到原子性的,但是set和expire则可以,这样我们就引入另外一个处理命令。
set lock x EX 10 NX
这个命令表示只有不存在key为lock才设置,有效时间是10s。这个命令是原子性的,从redis2.6.12版本开始支持。是不是以为这个命令实现分布式锁就是完美的了?并不是!使用这个只是说相对来说比较安全。为什么这么说,因为如果一个锁里面的执行超过了设置锁的超时时间,可能临界取区域的代码并不是安全的执行,这样可能其他线程或者服务就会同时操作同一份数据。
总结:
祝大家中秋快乐~~~