记一次利用jstack排查错误的过程

一直知道jstakc这个命令,却没有怎么真正使用过,正好项目上碰到了一些问题,利用jstack辅助定位到了问题。下面对整个过程进行一个记录。

 

问题的表象是,系统的用户接收接口一直失败,调用的时候会很久都没有响应。经过很长时间的等待之后,会返回一个504网关超时,或者500错误。在用postman进行调用后,系统的日志里面会出现进入方法的一行日志,但好像没有向下流转,像是卡在了某个地方。向上翻看服务器日志,有一些关于redis的报错,是获取不到redis连接。尝试重启服务器,问题依旧,有几次日志内容还会出现“打开的文件过多”。

 

后面尝试使用jstack来调出jvm的栈内容,既然调用用户接收接口会卡在某个地方,那么肯定会有一段执行时间很长的代码。调出来看看具体是卡在了哪一行。

 

首先输入ps -ef | grep tomcat,拿到tomcat的进程号。然后输入jstack -l [pid],发现打印出了大量的内容,由于猜想问题出在用户接收接口,所以使用包名来对输出的内容进行一些过滤。

 

输入jstack -l [pid] | grep hidm.core

这一次输出的内容就少多了,观察到输出的内容中,有一行指向了AccountServiceImpl.java这个文件的173行。赶紧去看源码,发现这是一行开启事务的代码。不禁疑惑,为啥开启事务的代码会卡住呢?联系之前看到的打开的文件过多,以及获取不到redis连接。开始推测,是不是哪里的事务出了问题,没有提交或者没有回滚呢?

 

接着看上一天的tomcat日志,发现里面有一个报错,也是出现在用户接收接口部分的代码中的,错误的内容是NoSuchMethodError。定位到那一行,调用了一个service。把服务器上这个service的class文件下载下来,用jd-gui工具进行反编译,发现内容是空的,很诡异。于是将代码重新编译,上传,重启服务器,重新调用用户接收接口,成功了。看来问题果然出现在这里。但为什么这里抛出的错误没有被抓取到呢?明明在try-catch块中,最外层的catch还是Exception。后来明白了,这里抛出的是一个Error,而不是Exception。Error和Exception都是继承于Throwable的,由于只对Exception进行了catch,所以这里抛出的Error没有被catch到。虽然在catch块中对事务进行了回滚,但由于Error没有被catch到,所以事务就没有被回滚。同时用户接收接口又会不停接收报文,每接收一条报文就会建立一个连接,开启一个事务。而Linux系统,用户可以开启的文件句柄是有限的,可以使用ulimit -n来查看,一般默认值是1024。网络连接同样也会占用这个文件句柄。本来启动项目就需要打开一些文件,同时用户接收接口由于出错,又没有释放连接,就导致了文件句柄被占满了。所以就出现了上面的“打开文件过多”,和redis无法获取连接的问题,因为无法再打开连接了。

 

最后,将catch的最外层改成了Throwable,这样Error和Exception都能被catch到,问题解决。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值