一次线上JVM问题的排查——一把无人持有的锁

本文详细记录了一次线上JVM问题的排查过程,问题表现为大量线程等待一把无人持有的锁。分析涉及代码bug查找、现场捕获、资源耗尽检查、框架层源码阅读等步骤,最终发现线程池结构失衡,特别是HSF框架中Provider与Consumer线程池比例严重失调,导致回环调用使应用服务能力下降,形成恶性循环,使得JVM运行缓慢甚至挂起。实验验证通过压测平台证实了问题的诱因,为解决此类问题提供了思路。

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

背景

近期,闲鱼核心应用出现了一个比较难解决的问题。在该应用集群中,会随机偶现一两个实例,其JVM运行在一个挂起的状态,深入分析stack文件发现,此时jvm中有大量的线程在等待一把没有任何线程持有的锁。问题实例所在的机器负载相对正常机器要轻很多,而其线程数则大幅增多。由于该问题在逻辑上的冲突,加上周边问题的复杂性,使得研究、分析、解决该问题变得相对来说困难与曲折。本文将系统性地介绍如何解决这个问题,并找出问题背后的原因。

问题分析

在实际解决这个问题的时候,我们发现不仅问题本身显得不合常理,其周边环境也相对来说不友善,给问题的分析与解决带来了较大的困难。

  • 集群中随机出现。问题随机出现在该应用集群中的一个或几个实例中,无法提前预知其出现规律。

  • 单机出现时间不可预知,现场捕捉困难,捕捉风险大,一般发现已经为事后,无现场第一手数据。从单个机器,或者单个实例看,则是出现概率非常低,出现时间完全随机。这使得蹲点单台机器以捕捉这个问题的思路几乎行不通,策略扩大至整个集群又可能出现稳定性及性能问题。

  • 问题出现频率低。出现频率大概在一到两天一次。

  • 问题表现复杂。该问题的表现很复杂,不仅从第一眼看去不合常理,JVM内部出现了大量线程在等待一把没有任何线程持有的锁。另外,问题机器的负载非常低,基本上在5%以内,相当于空载,而JVM中线程数却非常多,最多发现过接近4k个线程。

  • 问题周边环境复杂。该问题出现前后,应用先后引入了rxjava、协程,应用为早期应用,服务结构复杂,而log4j问题又和网上大量的文章情形不符。

  • 验证困难。理论分析完成后,无法在线上复现及验证,安全性、稳定性、数据等都不允许直接在线上验证。

解决方案

解决这个问题的主要按照以下六步,一步步排除法,最终定位并解决问题。按照先易后难,先直接后理论,先数据后源码的顺序,总结出来以下六步,大体上投入时间逐步增加,难度也逐渐增加。

step1. 代码bug查找

代码问题指的是业务代码本身逻辑问题把JVM带入了某种故障状态。问题的分析及排除很简单,通过观察应用日志即可。

step2. 现场捕获

定位了问题,问题也就解决了一半。

一般来说,定位问题主要有两个分类,即时定位,事后定位。
前一种是指我们实时直接监控JVM信息,在关键信息异常时,即发生动作。配合周期性的信息采集,基本可以对问题发生时刻前后数据精准采集和对比,做法一般是采用JVM代理方式或JMS方式。JVM代理分为C语言和Java语言代理,C语言代理运行在JVM层,可以做到即时Java代码发生

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值