关于redis分布式锁可能出现死锁的情况

来源:34-6 如何解决分布式锁中的重点难题

0沉默使者0

2023-06-06

老师想问您一下,您讲到redis分布式锁在代码出现异常时候可能会死锁,所以需要对锁使用过期机制。但是,您又提到为了防止程序运行时间过长导致锁提早过期而提出了续租,而实现续租的方式是在锁的acquire()时启动一个续租的线程。
所以我的问题是:
假设锁在acquire之后,后续业务逻辑代码出现了异常,但是这个异常是否有可能影响不到续租的那个线程?然后锁依然触发了续租的那个线程,导致这个锁还是没办法删除掉。。。
因此,这种情况下是否由于续租线程的存在反而又重新导致了死锁的可能性?该如何解决呢?

写回答

1回答

bobby

2023-06-10

你的问题提的很好,关于Redis分布式锁的过期与续租确实是在实际开发中需要面对的问题。

  1. 过期时间设计过短,会出现任务还没执行完,锁就已经过期的情况,可能导致锁的误删等问题;

  2. 过期时间设计过长,又会出现你说的这种情况,业务逻辑代码出现异常,锁未能及时释放,导致其他线程或者进程无法获得锁。

续租线程的作用就是解决过期时间设计过短的问题,但续租线程确实可能出现你提到的情况,也就是业务代码出现异常,但续租线程依然在运行。

针对这个问题,解决方案是在业务代码的异常处理部分手动中断续租线程或者设置一个标志来告诉续租线程停止续租。代码可能大致如下:

# 假设是Python代码
try:
    # 业务逻辑代码
except Exception as e:
    # 在这里捕获异常,然后中断续租线程
    stop_renewal_thread = True
    # 其他的异常处理逻辑

这样即使业务逻辑代码出现异常,我们也能保证锁最终会过期而不会出现死锁的情况。但是这种方案还是不能完全避免锁的误删问题,如果两个进程几乎同时请求锁,一个进程的锁过期,另一个进程获得锁,但第一个进程的续租线程可能把第二个进程的锁给误删了。所以在实际使用Redis分布式锁的时候,我们还需要给锁增加一个唯一的ID,只有持有这个ID的进程才能删除这个锁。

Redis分布式锁的正确使用是比较复杂的,需要考虑很多边界条件和异常情况,上面提到的是一种常见的解决方案,但实际使用还需要根据具体的业务场景进行调整。


0
0

Go+Python打造电商系统 自研微服务框架 抓紧高薪机遇

快速转型Go工程师,成为具备双语言后端能力的开发者

508 学习 · 530 问题

查看课程