阿尔萨斯官方社区正在举行征文活动,参加即有奖品拿哦~ 点击投稿
作者|张云翔
最近我们线上有个应用服务器有点上头,CPU总能跑到99%,我寻思着它流量也不大啊,为啥能把自己整这么累?于是我登上这台服务器,看看它到底在干啥!
以前碰到类似问题,可能会考虑使用 <代码>前惠普> 代码加 <代码> jstack 代码>命令去排查,虽然能大致定位到问题范围,但有效信息还是太少了,多数时候还是要靠猜。今天向大家推荐一款更高效更精准的工具: <代码>阿尔萨斯> 代码!阿尔萨斯是阿里巴巴开源的Java诊断工具,能够帮助我们快速定位线上问题。基本的安装使用可以参考官方文档: https://alibaba.github。io/阿尔萨斯
这次我们利用它来排查CPU负载高的问题.CPU负载过高一般是某个或某几个线程有问题,所以我们尝试使用第一个命令:> <代码> 线程代码,这个命令会显示所有线程的信息,并且把CPU使用率高的线程排在前面。
<前> <代码> [arthas@384]美元线程 新线程总数:112:0,可运行:26日,阻塞:0,等待:31日TIMED_WAITING: 55,终止:0 ID名称% CPU时间 108 h . .ec-0 RUNNABLE 51 4011:48 100 h . .ec RUNNABLE 48 4011:51 … 代码>为了方便阅读,删掉了一些不重要的信息
引用>可以看到、CPU资源几乎被前两个线程占满,并且已经执行了4000多分钟,我们服务器也就启动了两天,可见这两天它们是一刻也没闲着!那它们究竟在干什么呢?我们可以使用命令: <代码>线程id> 代码,查看线程堆栈。
<前> <代码> arthas@384线程108美元 “http - nio - 7001 - exec - 10“RUNNABLE Id=108 cpuUsage=51% c.g.c.c.HashBiMap.seekByKey (HashBiMap.java) c.g.c.c.HashBiMap.put (HashBiMap.java: 270) c.g.c.c.HashBiMap.forcePut (HashBiMap.java: 263) c.y.r.j.o.OaInfoManager.syncUserCache (OaInfoManager.java: 159) 代码>也可以使用线程- n 3命令打印出CPU占比最高的前三个线程,这差不多是在 <代码>前惠普> 代码比;,比; <代码> printf> 代码比;,比; <代码> jstack> 代码比;三令合一的效果了比;
引用>可以看的到,这个线程一直在执行 <代码> HashBiMap。seekByKey 代码>方法(可以重复执行几次 <代码>线程id 代码>确保该线程执行的方法没有时刻在变化),造成这个问题一般有两个原因:
<李> <代码> seekByKey 代码>方法被循环调用李> <李> <代码> seekByKey> 代码内部有死循环李>
先看一下是不是第一种,我们使用tt命令监听一下这个方法的调用情况:
<前> 100年<代码> tt - t com.google.common.collect.HashBiMap seekByKey - n 代码>注意:在线上执行这个命令的时候,一定要记得加上- n参数,否则线上巨大的流量可能会瞬间撑爆你的JVM内存执行结果显示, <代码> seekByKey 代码>方法并没有被一直调用,那大概率是 <代码> seekByKey 代码>方法内部有死循环。看下这个方法内部的逻辑,我们可以使用 <代码> jad com.google.common.collect.HashBiMap seekByKey 代码>命令反编译这个方法,这样做的好处是显得比较高端,不过我还是打算直接找到源码,说不定还有注释。源码如下:
<前> <代码>私人BiEntryseekByKey (@Nullable对象键,int keyHash) { (BiEntry 输入=hashTableKToV [keyHash,面具]; 入口!=零; 输入=entry.nextInKToVBucket) { 如果(keyHash==条目。keyHash,,对象。平等(关键,entry.key)) { 返回条目; } } 返回null; } 代码> 然后并没有注释,还好这个方法逻辑比较简单,也很容易看懂。
<李>通过哈希找到桶中,每个桶是一个链表,李> <李>遍历链表,找到这个关键对应的条目。这里要留意下输入的下一个节点是nextInKToVBucket,后文中会用的到。李>
发生了死循环,我们猜想可能是因为这个链表有环路。那么有没有办法验证这个猜想呢?答案是有!那么如何验证呢?首先我们要获得这个 <代码> HashBiMap> 代码对象,以便于查询对象里的数据。获得这个对象有很多办法,比如监听这个对象的某个方法,然后主动触发这个方法。这里向大家介绍一种更为通用的方法,这个方法在SpringMVC程序里非常好用。因为我们是SpringMVC应用,所有请求都会被
利用阿尔萨斯精准定位Java应用CPU负载过高问题