分布式锁的基本需求
- 互斥性:在任何时刻,只有一个客户端能持有锁。
- 无死锁:即使一个客户端在持有锁的期间崩溃,其他客户端也能获得锁。
- 容错性:分布式锁的实现应该能够容忍部分组件的失败,例如,锁服务节点的崩溃不应该影响客户端对锁的获取。
- 可重入性:同一个客户端可以多次获取同一把锁。
前言
为什么要使用分布式锁?
本地锁只能锁住单台机器多线程请求的资源
分布式锁是多台机器共同访问redis中的一个数据,只有获取到锁的线程才能访问
注意:
在更新MySQL和Redis之前,先获取一个分布式锁。这样,只有获取到锁的线程才能执行更新操作,从而避免了并发更新导致的数据不一致问题。
但是这种方法可能会导致性能下降和死锁的风险。因此,在使用分布式锁时需要谨慎考虑
如何设置分布式锁?
图解
注意:
SETNX(SET if Not eXists):这是Redis中实现锁机制的一个基本命令。SETNX命令会尝试将指定的键(key)设置为给定的值(value),如果键不存在的话。如果键已存在,则操作无效。这可以用于尝试获取锁的场景
返回值:1(不存在,设置成功)0(存在,设置不成功)
图表的解释
- 代码结束要释放锁
- 使用try-finally语句:在程序中,使用try-finally语句块来确保无论程序是否发生异常,finally块中的代码都会被执行。这样,你可以在finally块中添加释放锁的代码,以确保在程序中断时锁能够被正确释放。但是,这种方法无法解决服务器宕机或网络中断等极端情况。
- 设置锁的超时时间:为锁设置一个合理的超时时间,即使程序突然中断,锁也会在超时后自动释放。这可以通过Redis的EXPIRE命令或SET命令结合EX选项来实现。这样可以避免因为程序中断而导致的死锁问题。
如果锁设置的过期时间到了,但是程序还没有执行完,这种情况怎么解决?
解决方案:
1.增加锁的超时时间:如果任务确实需要较长时间来完成,并且你可以接受更长的等待时间,那么你可以考虑增加锁的超时时间。但请注意,过长的超时时间可能会增加死锁的风险,因为如果一个进程持有锁并因为某种原因崩溃或进入长时间阻塞状态,那么其他等待该锁的进程可能会被阻塞很长时间。
2.锁续命(Lock Renewal):如果锁支持续命操作(如Redisson中的看门狗机制),你可以尝试在锁到期之前重新设置或延长其超时时间。这通常通过一个定时任务或后台线程来实现,定期检查锁的状态并在需要时续命。但请注意,这需要在锁被释放之前完成,否则可能会导致竞争条件。
下面引入一张图解更好的理解看门狗机制