redisson使用lock导致死锁问题解决

 更新时间:2025年12月09日 11:04:17   作者:字节跳跃者  
本文主要介绍了redisson使用lock导致死锁问题解决,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

1、背景

我们是做物联网设备的公司,设备初始化会向设备发送API接口下发agora license,当时当时一个环境的全部agora设备都下发出现了问题,具体表现为:

  1. 当前的线程池告警持续触发拒绝策略(调度线程处理任务),导致运维要求我们进行排查
  2. 线程池资源告警则增加资源,环境中agora微服务已经增加到了6台,但是仍然线程的队列容量稳步上升,增加资源并不能解决问题
  3. 因为任务队列容量较多,导致大量agora设备下发agora都是在初始化的5-6h以后了,涉及设备面广,影响较大

2、排查方式

  1. 使用 jstack 1查看当前的线程池开头的线程状态与堆栈
  2. 发现全部的线程池的线程状态都是WATING状态,查看堆栈,都是在等待Redisson的锁释放
  3. 查看了下对应线程池设计的流程,发现在下发license时确实会tongguolock方法加锁
  4. 查看 腾讯云 日志,发现同一台设备在日志中频繁向设备下发agora license,10s一次,正常流程应当至少2min才初始化下发一次

经过逻辑分析后发现原因:

多个设备出故障频繁注册+redisson.lock() 强制等待锁释放造成线程池资源耗尽

以设备20252025为例,当下发设备license时,第一次会创建一个20252025的锁,但是这个设备也有其他在线程池的进程进行下发,因为使用的是lock,是无限期等待锁,所以线程池资源来利用不起来,导致触发拒绝策略

redisson创建分布式锁的lua脚本是

-- Lua 脚本(原子执行)
if (redis.call('exists', KEYS[1]) == 0) then
    redis.call('hset', KEYS[1], ARGV[2], 1);
    redis.call('pexpire', KEYS[1], ARGV[1]);
    return nil;
end;
if (redis.call('hexists', KEYS[1], ARGV[2]) == 1) then
    redis.call('hincrby', KEYS[1], ARGV[2], 1);
    redis.call('pexpire', KEYS[1], ARGV[1]);
    return nil;
end;
return redis.call('pttl', KEYS[1]);

可以看到value值(Value)的结构: 锁的值存储的是一个字符串(String),内容为锁 持有者的唯一标识符和可重入计数,格式为: :: ·UUID:Redisson客户端实例的唯一标识符(每个客户端启动时生成) ·ThreadID:持有锁的线程ID(支持可重入锁 同一线程多次加锁) ·Count:锁的可重入次数(初始为1,每次重入加1,释放时减1)

uuid为啥不变 猜测是服务pod没被杀 自己拉起来时候 这个客户端id不变导致的

在某一次的k8s滚动更新时,可能因为未在对应时间内执行完线程池任务(如最后30s等待关闭时间内,虽然没有新任务进,但是进程1在最后1s释放了锁,进程2在此时拿到了锁),导致finally代码块的解锁逻辑并未执行,导致该锁一直被占用,新pod启动后又给redLock续期导致该锁一直没有被释放

因为这两个原因导致线上出现问题

3、解决方式

  • 不能使用lock方法而是tryLock,等待一段时间后释放掉锁;并依据业务重要程度业务补救(如本次获取不到锁,很可能是因为当前有正在下发的任务,顾不需要延时任务或者持久化这种补救代码逻辑)且下发逻辑暂时不需要考虑Java代码层面幂等,数据库主键会保证幂等性
  • 推广一下,其他组件如ReentrantLock也有lock和trylock方法,在开发时也尽量使用tryLock

到此这篇关于redisson使用lock导致死锁问题解决的文章就介绍到这了,更多相关redisson使用lock导致死锁内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • java 中enum的使用方法详解

    java 中enum的使用方法详解

    这篇文章主要介绍了java 中enum的使用方法详解的相关资料,希望通过本文能帮助到大家,理解掌握java 中enum的使用方法,需要的朋友可以参考下
    2017-09-09
  • IDEA解决springboot热部署失效问题(推荐)

    IDEA解决springboot热部署失效问题(推荐)

    热部署,就是在应用正在运行的时候升级软件,却不需要重新启动应用。这篇文章主要介绍了IDEA解决springboot热部署失效问题,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-09-09
  • Java服务调用失败报Service com.oneinfinite.adflow.api.service.TestService未找到的解决方法

    Java服务调用失败报Service com.oneinfinite.adflow.api.service.T

    在Java开发中,服务调用是常见的操作,尤其是在微服务架构中,然而,服务调用过程中可能会遇到各种问题,下面我们来看看如何解决Service com.oneinfinite.adflow.api.service.TestService with version 0.0.0 not found的问题吧
    2025-03-03
  • Java全面细致讲解final的使用

    Java全面细致讲解final的使用

    关于final关键字,它也是我们一个经常用的关键字,可以修饰在类上、或者修饰在变量、方法上,以此看来定义它的一些不可变性!像我们经常使用的String类中,它便是final来修饰的类,并且它的字符数组也是被final所修饰的。但是一些final的一些细节你真的了解过吗
    2022-05-05
  • SpringBoot+MybatisPlus+Mysql+JSP实战

    SpringBoot+MybatisPlus+Mysql+JSP实战

    这篇文章主要介绍了SpringBoot+MybatisPlus+Mysql+JSP实战,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-12-12
  • Java Math类的三个方法ceil,floor,round用法

    Java Math类的三个方法ceil,floor,round用法

    这篇文章主要介绍了Java Math类的三个方法ceil,floor,round用法,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-07-07
  • springboot项目突然启动缓慢的解决

    springboot项目突然启动缓慢的解决

    这篇文章主要介绍了springboot项目突然启动缓慢的解决,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-11-11
  • Spring Security注解失效的五大陷阱与避坑指南(你踩几个坑)

    Spring Security注解失效的五大陷阱与避坑指南(你踩几个坑)

    本文解析SpringSecurity注解权限控制的五大陷阱,如未启用@EnableMethodSecurity、自调用绕过代理、异常静默处理等,提醒开发者需正确配置和测试,确保权限逻辑有效执行,感兴趣的朋友跟随小编一起看看吧
    2025-09-09
  • SpringBoot动态生成接口实现流程示例讲解

    SpringBoot动态生成接口实现流程示例讲解

    最近遇到一个需求,需要在程序运行过程中,可以动态新增接口,自定义接口参数名称,基本类型,以及请求方法,请求头等等。通过几天的研究,找到了我需要的解决方案
    2023-01-01
  • 详解java.lang.reflect.Modifier.isInterface()方法

    详解java.lang.reflect.Modifier.isInterface()方法

    这篇文章主要介绍了详解java.lang.reflect.Modifier.isInterface()方法的相关资料,这里提供实例帮助大家理解这个方法的使用,需要的朋友可以参考下
    2017-09-09

最新评论