Redis分布式锁在分布式场景下的问题及解决方法

1. 死锁问题

  • 场景:
    当用 redis 做分布式锁时,当 A 用户竞争锁成功,A 用户所在的主机挂了,这时候还没有来得及释放锁,那么其他用户去用 setnx 指令去竞争锁时发现 redis 有这个锁的 key,所以就导致其他用户永远都竞争不成功。

解决方案: 当用户加锁成功时给锁设置一个跟业务执行时间匹配的锁失效时间, 这样就算锁没有释放过一段时间锁也会实现,其他用户就可以竞争到锁了(这里在设置失效时间的操作,要和 setnx 指令一起执行,不能分成2步执行,否则在setnx之后,还没来得及设置失效时间,主机挂了,还是会发生死锁)。

2. 锁续命问题

  • 场景:
    当 A 用户获取锁成功,但是 A 执行业务操作的时间比较长,就可能会导致业务执行时间大于锁失效时间,那么 A 还在执行业务,锁失效了,就会导致其他用户也可以成功竞争到锁,这样就没办法很好的锁住业务,就会导致脏数据的出现。

解决办法: 当 A 竞争到锁时,就需要开启一个 timer 对锁续命,续命就是重新设置锁的失效时间,由定时器定时的去做这件事情。业务操作完成,unlock,timer.cancel()。

3. 主从锁失效的问题

  • 场景:
    当 redis 是一个主从架构时,当 A 用户从 master 节点获取到了锁,这时候出现这么一个情况,这个锁没有及时同步到 slave 节点时,master 节点挂了,由 redis 哨兵做了主从切换,以前的 slave 成了主,而这时 slave 是没有锁的这个 key 的,那么就会导致其他用户也可以成功竞争到锁进行业务操作,从而导致脏数据。

解决方案: 这时候可以从奇数台 redis 节点去获取锁,如果超过半数的节点能成功获取到锁,并且获取锁的耗时要小于设置的锁失效时间时就认为获取锁成功了,反之就失败。
这里注意两个点:
1、获取锁的时间,获取时间必须要小于锁失效时间
2、必须超过半数节点获取锁成功
如果这两点没有达到则会执行 unlock 操作释放各节点的锁。

  • 这种方案因为需要和多个redis进行通信,执行效率会很低。

上面提到的3个问题都可以使用Redis官方推荐的Java版的Redis客户端Redisson解决,它提供的功能非常多,也非常强大
https://github.com/redisson/redisson

  • Reentrant Lock解决死锁和锁续命问题

Redis分布式锁在分布式场景下的问题及解决方法

  • ResLock解决主从锁失效的问题

Redis分布式锁在分布式场景下的问题及解决方法