JVM常见问题排查系列【003】 常用命令案例

书接上篇:上篇介绍了 jmap 命令 主要是查堆的相关情况

1.jstack : Java堆栈跟踪工具 (可以自己参阅 深入理解JAVA虚拟机 书籍)

jstack (stack Trace for java )命令用于生成虚拟机当前时刻的线程快照(一般称为threaddump 或者javacore文件)。线程快照就是当前虚拟机内每一条线程正在执行的方法堆栈的集合,生成线程快照的主要目的是定位线程出现长时间停顿的原因,如线程间死锁,死循环,请求外部资源导致的长时间等待都是导致线程长时间停顿的原因。线程出现停顿的时候通过jstack来查看各个线程的调用堆栈,就可以知道没有响应的线程到底在后台做什么事情,或者等待什么资源。

jstack 命令格式:

 jstack [option] vmid

option 选项的合法值与具体含义如下表:

选项 作用
-F 当正常输出的请求不被响应时,强制输出线程堆
-l 除堆栈外,显示关于锁的附加信息
-m 如果调用到本地方法的话,可以显示C/C++的堆栈

 

具体案例:

 

案例解析1:

最近遇到了一个问题,接手维护公司一个boss后台管理系统,此系统就是公司内部用,平时发布一些文章,资讯,系统后台有两个定时任务,按正常情况说,这样的系统,没有什么技术挑战。但是运行一段时间后,发现运营人员反馈系统请求无响应,因为是后台管理系统,直接在启动脚本上添加gc打印信息,并输出到相关文件中,重启先让用户使用。但是后来,隔山差五的出现这个问题,经过分析GC日志,发现 总共500M的内存,收集后,都恢复正常。证明堆配置各方面没有问题。

在运维人员反馈访问不了后,直接拿命令

此命令:

jstack -l 30999 >> boss.stack

记得中间加空格

将stack日志输出到money.stack文件里面,然后拷贝到本机电脑上直接拿UE编辑器打开,发现redis连接大量锁等待,

经过代码搜索,发现有个添加文章的地方,有使用到reids来统计文章的发布次数,采用最原始的方式获取连接,没有释放。

后台管理系统配置reids最大连接5个,经过分析,基本够用。直接修复此BUG。

具体的 分析日志,随后贴出来。

 

具体stack日志如下:(截取片段) 注意看标红色的

 

"http-nio-6022-exec-278" #13717 daemon prio=5 os_prio=0 tid=0x00007f2de803b800 nid=0x5aa9 waiting on condition [0x00007f2db7d76000]
   java.lang.Thread.State: WAITING (parking)
    at sun.misc.Unsafe.park(Native Method)
    - parking to wait for  <0x00000000d6309d00> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)
    at java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)
    at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:2039)
    at org.apache.commons.pool2.impl.LinkedBlockingDeque.takeFirst(LinkedBlockingDeque.java:590)
    at org.apache.commons.pool2.impl.GenericObjectPool.borrowObject(GenericObjectPool.java:441)
    at org.apache.commons.pool2.impl.GenericObjectPool.borrowObject(GenericObjectPool.java:362)
    at redis.clients.util.Pool.getResource(Pool.java:49)
    at redis.clients.jedis.JedisPool.getResource(JedisPool.java:226)
    at redis.clients.jedis.JedisPool.getResource(JedisPool.java:16)
    at org.springframework.data.redis.connection.jedis.JedisConnectionFactory.fetchJedisConnector(JedisConnectionFactory.java:276)
    at org.springframework.data.redis.connection.jedis.JedisConnectionFactory.getConnection(JedisConnectionFactory.java:469)
    at org.springframework.data.redis.core.RedisConnectionUtils.doGetConnection(RedisConnectionUtils.java:132)
    at org.springframework.data.redis.core.RedisConnectionUtils.getConnection(RedisConnectionUtils.java:95)
    at org.springframework.data.redis.core.RedisConnectionUtils.getConnection(RedisConnectionUtils.java:82)
    at org.springframework.data.redis.core.RedisTemplate.execute(RedisTemplate.java:211)
    at org.springframework.data.redis.core.RedisTemplate.execute(RedisTemplate.java:184)
    at org.springframework.data.redis.core.AbstractOperations.execute(AbstractOperations.java:95)
    at org.springframework.data.redis.core.DefaultValueOperations.set(DefaultValueOperations.java:218)
    at com.jianlc.bos.service.impl.redis.RedisCacheServiceImpl.setString(RedisCacheServiceImpl.java:77)
    at com.jianlc.bos.common.shiro.ShiroRealm.doGetAuthenticationInfo(ShiroRealm.java:141)
    at org.apache.shiro.realm.AuthenticatingRealm.getAuthenticationInfo(AuthenticatingRealm.java:571)

    at org.apache.shiro.authc.pam.ModularRealmAuthenticator.doSingleRealmAuthentication(ModularRealmAuthenticator.java:180)
    at org.apache.shiro.authc.pam.ModularRealmAuthenticator.doAuthenticate(ModularRealmAuthenticator.java:267)
    at org.apache.shiro.authc.AbstractAuthenticator.authenticate(AbstractAuthenticator.java:198)
    at org.apache.shiro.mgt.AuthenticatingSecurityManager.authenticate(AuthenticatingSecurityManager.java:106)
    at org.apache.shiro.mgt.DefaultSecurityManager.login(DefaultSecurityManager.java:274)
    at org.apache.shiro.subject.support.DelegatingSubject.login(DelegatingSubject.java:260)
    at com.jianlc.bos.common.util.UserUtil.login(UserUtil.java:31)
    at com.jianlc.bos.controller.login.LoginController.login(LoginController.java:120)
    at sun.reflect.GeneratedMethodAccessor214.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:209)

 

经过stack日志分析,服务不能访问是由于redis连接不够用导致的,但是一个公司内部的后台管理系统,目前配置了连接池5个连接,按道理说够用,然后根据日志搜索代码,发现有个开发人员获取redisConnection后没有释放,导致添加文章保存后,把连接给占完了,导致服务不可用,此时堆方面的数据正常,栈方面不够用。拉取分支,修复BUG,上线后问题解决。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章