Redis用setnx+expire实现分布式锁存在什么隐患,如何改进?

用Redis实现分布式锁,2.6.12之前版本方案:setnx加锁,del释放锁,如果锁没释放,设置过期时间,到了时间,del释放锁。但是,这会存在一些问题。

  1. setnx和expire不是原子操作一旦redis宕机,expire没有设置成功,锁就无法释放。只有一个请求的setnx可以成功,任何一个请求的expire都可以成功。请求比较密集,过期时间一直刷新,导致锁一直有效。
  2. 超时后,删除其他线程的锁。在线程A执行过程中,锁已释放,A还未在执行业务,但是还未删除锁。线程B获取锁执行业务,线程A执行完,A误删B的锁。
  3. 多个线程并发获取锁、释放锁。同一时间有线程A、B在访问同一代码块。

对于上面的隐患,Redis已改善。下面,我们针对隐患逐一改善。

  1. Redis2.6.12以上版本,可以用set获取锁。set可以实现setnx和expire,这个是原子操作。
  2. Lua删除锁。Lua是原子操作。
  3. 让获取锁的线程开启一个守护线程,给线程还没执行完,又快要过期的锁续航。大概是这样的,线程A还没执行完,守护线程每当快过期时,延时expire时间。当线程A执行完,显示关闭守护线程。如果中间宕机,锁超过超时,守护线程也不在了,自动释放锁。

 

posted @ 2020-04-01 20:10  Ivy_Xu  阅读(6137)  评论(0编辑  收藏  举报