簡體   English   中英

tomcat中的Java Web應用程序會定期凍結

[英]Java web app in tomcat periodically freezes up

我的運行Tomcat(7.0.28)的Java Web應用程序會定期無響應。 我希望得到一些可能的罪魁禍首(同步?)的建議,以及一些推薦的工具,用於收集有關崩潰期間發生的事情的更多信息。 我積累的一些事實:

  • 當Web應用程序凍結時,tomcat繼續將請求線程提供給應用程序,但應用程序不會釋放它們。 線程池填滿最大值(當前為250),然后后續請求立即失敗。 在正常操作期間,永遠不會有超過2或3個活動線程。

  • 發生問題時,沒有任何錯誤或異常記錄到我們的任何tomcat或Web應用程序日志中。

  • 通過tomcat管理Web應用程序在我們的應用程序上執行“停止”然后“啟動”可以立即解決此問題(直到今天)。

  • 最近頻率已經是一天兩到三次,雖然今天更糟糕,可能是20次,有時候不會立即恢復生機。

  • 問題僅在工作時間發生

  • 我們的登台系統不會出現此問題

  • 出現問題時,服務器上的處理器和內存使用率保持不變(並且相當低)。 Tomcat報告了大量的可用內存。

  • 發生問題時,Tomcat會繼續響應。 管理Web應用程序運行良好,tomcat繼續向我們的應用程序發送請求,直到池中的所有線程都被填滿。

  • 發生問題時,我們的數據庫服務器保持響應。 我們使用Spring框架進行數據訪問和注入。

  • 當使用率很高時通常會出現問題,但使用率從未出現異常高的峰值。

  • 問題歷史:大約一年半前發生過類似的事情。 在許多服務器配置和代碼更改后,問題消失,直到大約一個月前。 在過去的幾周里,它的發生頻率更高,平均每天2到3次,有時連續幾次。

  • 我今天發現了一些可能沒有線程安全的服務器代碼,我為此修好了,但問題仍在發生(盡管不那么頻繁)。 這是非線程安全代碼可能導致的問題嗎?

更新:有幾個帖子暗示數據庫連接池耗盡,我做了一些搜索,發現了另一個Stackoverflow問題 ,它解釋了我遇到的幾乎所有問題。

顯然,Apache的BasicDataSource實現中maxActive和maxIdle連接的默認值均為8.此外,maxWait設置為-1,因此當池耗盡並且有新的連接請求進入時,它將永遠等待而不記錄任何有點例外。 我仍然要等待這個問題再次發生並在JVM上執行jstack轉儲,以便我可以分析該信息,但看起來這就是問題所在。 它唯一沒有解釋的是為什么應用程序有時無法從這個問題中恢復。 我認為這些請求有時會堆積起來,一旦它落后,就永遠無法趕上。

更新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為3秒,以確保我們開始查看池填滿時記錄的異常。 然后我會將這些值設置為適當的值並進行監控。

更新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.我將監視一段時間,但我的猜測是這是問題的結束。

根據經驗,您可能希望查看數據庫連接池實現。 可能是您的數據庫具有足夠的容量,但應用程序中的連接池僅限於少量連接。 我不記得細節,但我似乎記得有一個類似的問題,這是我改用BoneCP的原因之一,我發現在負載測試下它非常快速和可靠。

嘗試下面建議的調試后,嘗試增加池中可用的連接數,看看是否有任何影響。

我今天發現了一些可能沒有線程安全的服務器代碼,我為此修好了,但問題仍在發生(盡管不那么頻繁)。 這是非線程安全代碼可能導致的問題嗎?

這取決於你的線程安全意味着什么。 聽起來好像你的應用程序導致線程死鎖 您可能希望運行生產環境,並將JVM配置為允許調試器連接,然后使用JVisualVM,JConsole或其他分析工具(YourKit是優秀的IMO)來查看您已獲得的線程以及它們是什么等待。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM