linux下tomcat shutdown後 java進程依舊存在 -- 阿里MetaQ篇


此篇文章描述的症狀和上一篇文章一致(即執行tomcat ./shutdown.sh 後,雖然tomcat服務不能正常訪問了,但是ps -ef | grep java 後,發現tomcat對應的java進程未隨web容器關閉而銷燬,進而存在殭屍java進程),但是處理的過程不一致,所有又單開了一篇blog來寫。


我在另外一個項目中使用到了阿里的MetaQ消息中間件,然後shutdown tomcat 發現java進程依舊存在,沿用上一篇文章的思路,我最開始以爲是本地代碼中scheduledExecutorService沒有及時關閉,但check code後發現scheduledExecutorService 已經進行了shutdown處理。於是只能從jstack dump跟蹤,./jps   查詢到對應的pid,然後 ./jstack  pid,發現存在如下一個非守護線程的dump:

"notify-remoting-ScanAllConnection-1-thread-1" prio=10 tid=0x00007f6124956000 nid=0x2cda waiting on condition [0x00007f6149544000]
   java.lang.Thread.State: TIMED_WAITING (parking)
        at sun.misc.Unsafe.park(Native Method)
        - parking to wait for  <0x00000000f04a5958> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)
        at java.util.concurrent.locks.LockSupport.parkNanos(LockSupport.java:226)
        at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.awaitNanos(AbstractQueuedSynchronizer.java:2082)
        at java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take(ScheduledThreadPoolExecutor.java:1090)
        at java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take(ScheduledThreadPoolExecutor.java:807)
        at java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1043)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1103)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:603)
        at java.lang.Thread.run(Thread.java:722)

上述dump對應的代碼是Gecko中,com.taobao.gecko.service.impl.BaseRemotingController類,發現此類中存在一個ScheduledExecutorService scanAllConnectionExecutor,然後我竊以爲是此處未shutdown,但,非也,阿里coder的代碼不會出現如此低劣的漏洞的,遵循問題定位原則:出現bug時先確保不是自己的代碼出現問題,我又看了一遍項目中涉及到metaq的代碼,驚奇的發現,雖然一再強調MessageSessionFactory、MessageProducer、MessageConsumer 應該是單例複用形式存在,項目中我是採用spring來託管singleton的,然後,在創建MessageProducer時,卻沒有使用已經singleton的MessageSessionFactory,而是又重新new 出一個 MessageSessionFactory 實例,而且shutdown時只shutdown spring託管的實例,重新new 出來的對象並未對其進行shutdown。正是該原因,導致Gecko中的scanAllConnectionExecutor一直處於timed_waiting 狀態,進而導致jvm無法正常退出


此次bug定位耗時近一天,最開始我甚至以爲是Gecko的bug,但事實證明,出問題往往是自己!引此爲戒 :)


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