Redisson(1)分布式锁——如何解决死锁问题

本文探讨Redisson解决分布式锁死锁问题的方法。普通Redis实现分布式锁时,业务机器或Redis宕机可能导致死锁。Redisson通过设置lockWatchdogTimeout参数,默认30秒,解决业务机器宕机问题;对于Redis宕机,官方文档虽有描述,但存在歧义,还需看解锁操作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 Redisson是如何解决死锁问题的?

普通利用Redis实现分布式锁的时候,我们可能会为某个锁指定某个key,当线程获取锁并执行完业务逻辑代码的时候,将该锁对应的key删除掉来释放锁。

lock->set(key),成功->执行业务,业务执行完毕->unlock->del(key)。

根据这种操作和实践方式,我们可以分为下面两个场景:

1)业务机器宕机

因为我们的业务不知道要执行多久才能结束,所以这个key我们一般不会设置过期时间。这样如果在执行业务的过程中,业务机器宕机,unlock操作不会执行,所以这个锁不会被释放,其他机器拿不到锁,从而形成了死锁。

Redisson为了解决这种情况,设定了一个叫做lockWatchdogTimeout的参数,默认为30秒钟。这样当业务方调用加锁操作的时候,

默认的leaseTime是-1,此时看门狗才会生效,不会走if分支,如果leaseTime被人为设置了值,且不是-1,看门狗不会work。这里会取watch dog的时间作为锁的持有时间,默认是30s,这个时候即使发生了宕机现象,因为这个锁不是永不过期的(宕机之后不不会再续租),所以30s后就会释放,不会产生死锁。

另一方面,它还能解决当锁内逻辑超过30s的时候锁会失效的问题,因为当leaseTime是-1的时候,会启动一个定时任务,在业务方释放锁之前,会一直不停的增加这个锁的生命周期时间,保证在业务执行完毕之前,这个锁一直不会因为redis的超时而被释放(具体参考:汪~汪~汪~redisson的WatchDog是如何看家护院的?_黑少的技术盒子-CSDN博客)。

2)Redis宕机

如果Redis宕机,三种情况:

①Redis是单点模式

②Redis是集群模式,master在获取到一把锁之后(写操作成功后),在没来得及把该锁同步到slave之前就宕掉,这个时候slave没有锁,这把锁失效了……

③Redis是集群模式,而整个集群都宕机,那么就没救了……

Redisson的官方文档里有这段描述(参考:8. Distributed locks and synchronizers · redisson/redisson Wiki · GitHub

“If Redisson instance which acquired lock crashes then such lock could hang forever in acquired state. To avoid this Redisson maintains lock watchdog, it prolongs lock expiration while lock holder Redisson instance is alive. By default lock watchdog timeout is 30 seconds and can be changed through Config.lockWatchdogTimeout setting.”

这里说的是拥有Redisson的服务(业务服务)宕机造成的影响吗?如果是,那么和上面说的1)是一个意思。

这里GitHub中文译文翻译可能会引起歧义,8. 分布式锁和同步器 · redisson/redisson Wiki · GitHub

里面翻译的是:

“大家都知道,如果负责储存这个分布式锁的Redisson节点宕机以后,而且这个锁正好处于锁住的状态时,这个锁会出现锁死的状态。为了避免这种情况的发生,Redisson内部提供了一个监控锁的看门狗,它的作用是在Redisson实例被关闭前,不断的延长锁的有效期。默认情况下,看门狗的检查锁的超时时间是30秒钟,也可以通过修改Config.lockWatchdogTimeout来另行指定。”

这里说“负责储存这个分布式锁的Redisson节点宕机”可能会引起歧义,Redisson应该指的是客户端,而不是Redis服务实例吧。

如果是要形容Redis有问题而业务系统没问题,应该描述为“如果存储该锁的Redis节点宕机,那么这个锁可能会被无限hang住”。

但是这里为什么会无限hang住,还是要看解锁的部分是如何操作的,后面也会详细说明。(这里貌似是因为Redis的订阅功能,只有当这个锁释放的时候,才会触发所有订阅该锁的其他线程,否则其他线程永远都获取不到锁[如果没有调用带有超时时间获取锁的方法的话],从而造成死锁。这个后面再详细说,这里说的只是猜测,可能并不准确)。

反之,如果不hang住,锁因为Redis节点宕掉而失效,那么其他的线程可以获取锁,但是当前的业务系统还在处理业务,并没有处理完,这里就会有线程安全问题了。

参考:

汪~汪~汪~redisson的WatchDog是如何看家护院的?_黑少的技术盒子-CSDN博客

8. Distributed locks and synchronizers · redisson/redisson Wiki · GitHub

相关文档连接:

Redis官方文档中文链:《Redis官方文档》用Redis构建分布式锁 | 并发编程网 – ifeve.com

Redisson Github中文链接:目录 · redisson/redisson Wiki · GitHub

Redisson Github文档:Home · redisson/redisson Wiki · GitHub

Redisson 官方文档:Redisson: Redis Java client with features of In-Memory Data Grid

其他链接:扒开Redisson的小棉袄,Debug深入剖析分布式锁之可重入锁No.1_黑少的技术盒子-CSDN博客redisson应用之分布式对象 | KL博客

掘金

### 使用 Redisson 实现分布式锁时的注意事项及解决方案 #### 锁超时设置不当 不合理的锁超时时间可能导致死锁或者短暂时间内无法获取锁的情况。过短的时间可能使操作未完成前锁已释放,而过长时间则会阻碍其他线程及时获得锁。 为了应对这一挑战,建议基于具体应用场景评估并设定合适的锁等待时间和保持活动时间(TTL)。利用Redisson内置的心跳检测功能——即看门狗机制,可以在一定程度上自动延长有效期内即将到期的锁的有效期[^1]。 ```java RLock lock = redissonClient.getLock("anyLock"); lock.lock(10, TimeUnit.SECONDS); // 设置显式的持有时间为10秒 ``` #### 资源竞争激烈情况下的性能瓶颈 在高并发环境下,大量客户端尝试同时获取同一把锁会造成严重的争用现象,影响整体吞吐量和响应速度。 针对此问题,可以通过优化业务逻辑减少不必要的同步区域范围;另外就是调整Redis实例配置参数以增强其处理能力,比如增大连接池大小、合理分配内存等措施来缓解压力。此外,还可以考虑引入限流策略控制请求速率,从而减轻服务器负担[^2]。 #### 客户端异常断开后的数据残留风险 当某个持有者因程序崩溃等原因意外终止运行后未能正常解锁,则该对象会被永久锁定直到达到预设的最大租约期限为止。这不仅浪费了宝贵的系统资源而且还容易引发后续一系列连锁反应。 为了避免这种情况的发生,除了前面提到过的启用续命守护进程外,还应该定期清理那些长期无人认领的对象记录,并确保所有涉及加解密过程的操作都具备良好的健壮性设计,能够妥善处理各种边界条件以及突发状况。例如: - 配置`forceRenewalNearExpireOnly=false`属性让每次续约都会更新整个生命周期; - 启动后台任务定时扫描数据库表查找超过一定年龄阈值仍未被回收的数据项加以清除。 ```properties redisson { ... locksWatchdogTimeout=30000 # 单位毫秒,默认30秒 } ``` #### 多数据中心环境的一致性保障难题 对于跨地域分布式的大型互联网平台而言,如何保证各地机房之间的状态同步成为一大技术难点所在。由于网络延迟等因素的影响,可能会造成部分节点间的信息不对称进而破坏全局视角下单一版本的事实标准。 解决办法之一便是借助于一些成熟的第三方中间件产品如Zookeeper、Etcd之类的服务注册中心来进行辅助管理,它们内部实现了强一致性的选举协议Paxos/Raft算法,能够在较短时间内达成共识并将最新变更广播出去供各成员知晓遵循执行。当然也可以直接选用支持多活架构特性的高级版Redis企业级套件Enterprise Edition作为底层存储引擎。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值