運行Tomcat(7.0.28)的我的Java Web應用程序定期變得無響應。我希望提供一些關於可能的罪魁禍首(同步?)的建議,以及一些推薦的工具,用於收集有關崩潰期間發生的事情的更多信息。我已經積累了一些事實:tomcat中的Java Web應用程序定期凍結
當Web應用程序死機,Tomcat的繼續請求的線程送入應用程序,但應用程序不釋放他們。線程池填充到最大值(當前爲250),然後後續請求立即失敗。在正常操作期間,永遠不會有超過2或3個活動線程。
有沒有錯誤或出現問題時,記錄到我們的任何Tomcat或web應用程序日誌的任何類型的異常。
做經由Tomcat的管理Web應用程序我們的應用程序「停止」,然後在「開始」立即修復此問題(直到今天)。
最近的頻率已非一日兩兩三次,雖然今天是差多了,大概20次,有時不能馬上恢復生機。
問題在營業時間內
我們的分期系統
發生問題時不會發生的問題,在服務器上的處理器和內存使用率保持平坦(和相當低的)只發生。 Tomcat報告大量可用內存。
當問題發生時,Tomcat會繼續響應。管理Web應用程序運行得非常好,並且tomcat繼續向我們的應用程序發送請求,直到池中的所有線程都被填充。
發生問題時,我們的數據庫服務器保持響應。我們使用Spring框架進行數據訪問和注入。
問題通常當使用率較高的發生,但有沒有在使用一個非常高的尖峯。
問題的歷史:類似的事情發生在大約一年半前。在許多服務器配置和代碼更改之後,問題在大約一個月前消失。在過去的幾周裏,它發生得更爲頻繁,平均每天2-3次,有時甚至連續幾次。
我今天可能不是線程安全的發現了一些服務器代碼,我把一個修復程序爲,但問題仍然發生(儘管不那麼頻繁)。這是非線程安全代碼可能導致的問題嗎?
UPDATE:隨着幾個職位提示數據庫連接池耗盡,我沒有在這個方向的一些搜索,發現這個其他Stackoverflow question這也解釋了幾乎所有我遇到的問題。
顯然,Apache的BasicDataSource實現中的maxActive和maxIdle連接的默認值每個都是8.此外,maxWait設置爲-1,因此當池耗盡並且連接的新請求進入時,它將等待永遠不會記錄任何異常。我仍然會等待這個問題再次發生,並在JVM上執行jstack轉儲,以便我可以分析這些信息,但看起來像是這個問題。它唯一不解釋的是爲什麼應用程序有時不能從這個問題中恢復。我想這些請求有時只是堆積起來,一旦落後,它永遠無法趕上。
UPDATE II:我崩潰期間跑了jstack,發現以下的約250(最大線程數):
"http-nio-443-exec-294" daemon prio=10 tid=0x00002aaabd4ed800 nid=0x5a5d in Object.wait() [0x00000000579e2000]
java.lang.Thread.State: WAITING (on object monitor)
at java.lang.Object.wait(Native Method)
at java.lang.Object.wait(Object.java:485)
at org.apache.commons.pool.impl.GenericObjectPool.borrowObject(GenericObjectPool.java:1118)
- locked <0x0000000743116b30> (a org.apache.commons.pool.impl.GenericObjectPool$Latch)
at org.apache.commons.dbcp.PoolingDataSource.getConnection(PoolingDataSource.java:106)
at org.apache.commons.dbcp.BasicDataSource.getConnection(BasicDataSource.java:1044)
at org.springframework.jdbc.datasource.DataSourceUtils.doGetConnection(DataSourceUtils.java:111)
at org.springframework.jdbc.datasource.DataSourceUtils.getConnection(DataSourceUtils.java:77)
at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:573)
at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:637)
at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:666)
at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:674)
at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:718)
爲了我的未經訓練的人,這看起來相當確鑿。看起來數據庫連接池已經達到了上限。我在不修改maxActive和maxIdle的情況下配置了maxWait三秒,以確保在池填滿時我們開始查看記錄的異常情況。然後,我會將這些值設置爲適當的值並進行監控。
UPDATE III:配置MAXWAIT後,我開始看到這些在我的日誌,符合市場預期:
org.apache.commons.dbcp.SQLNestedException: Cannot get a connection, pool error Timeout waiting for idle object
at org.apache.commons.dbcp.PoolingDataSource.getConnection(PoolingDataSource.java:114)
at org.apache.commons.dbcp.BasicDataSource.getConnection(BasicDataSource.java:1044)
at org.springframework.jdbc.datasource.DataSourceUtils.doGetConnection(DataSourceUtils.java:111)
at org.springframework.jdbc.datasource.DataSourceUtils.getConnection(DataSourceUtils.java:77)
我已經設置maxActive爲-1(無限)和了maxidle到10.我會監視一段時間,但我的猜測是,這是問題的結束。
'殺-3'是你的朋友。運行這個並看看線程轉儲。您可能需要查看線程轉儲分析器以進行信息分組(http://java.net/projects/tda/)。 –
mindas
2012-07-11 20:40:39
沒有任何其他信息的Wild-guess(需要線程轉儲!):數據庫連接池耗盡。 – 2012-07-12 00:38:43
這正是發生了什麼事對我來說,web應用變得太大,最大連接數過低,等待時間undifined,線程就一直堆放everynow然後和服務器將凍結。增加最大利弊,並設置最大等待的具體時間,現在我只是監測,但服務器運行良好。感謝這個迷你教程。 – Lauro182 2015-06-11 18:18:13