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,上線後問題解決。

 

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