1. 程式人生 > >解決Tomcat資料連線池無法釋放

解決Tomcat資料連線池無法釋放

近段時間,公司的檢測中心報表系統(SMC)的開發人員時不時找到我,說使用者老是出現無法登入的情況。前些日子因為手頭上有 Jboss 叢集的測試工作,發現使用者不能登入時,都是在 Tomcat 中將這個專案 Reload 一下就好了,不過只是治標而已,因為大概幾個小時之後又會再次出現無法登入的情況。

今天上午,開發人員小毛又找到我,要我協助將這個問題根治一下,拖太久使用者難保不投訴。

簡單分析了一下,每次 Reload 一下就能解決無法登入的情況,自然而然就想到是不是 session 有問題呢?於是到 Tomcat 的 manager 介面看了下,發現並沒有出現 session 粘滯暴漲的情況。

本來可以開啟 jconsole 看看的,正好想起了之前用過的 Tomcat 檢測工具:probe,於是直接從其他機器上 scp 了一個 probe.war,丟到了 webapps 下面自動部署。

部署完之後,打開了 probe 網頁管理後臺發現 smc 專案的實時資料庫連線數很高,而且只增不減!這個系統的資料池大小設定為 200,此時已經是 100+了,而且一直只升不降。好吧,當資料連線數達到 200 時,問題肯定會再次出現的。

於是我將這個問題告訴了小毛,要他自己去修改連線池釋放機制(這裡用的是專案單獨設定的引數)。他說試過了,沒有用,問下我有沒有辦法。

我這人記性一直欠佳,也很少去記憶一些引數設定,問我麼?還我也只能問 BD、GG 了。。。

最終在強大的搜尋引擎的幫助下,找到了相關引數說明,通過參考修改後成功解決了問題!

Tomcat 連線池無法釋放的解決方法:

編輯專案的連線池配置檔案:context.xml,參考下面的【資料庫連線設定】引數說明,按照實際情況調整好各項數值,尤其是 Maxidle 和 maxActive。並記得加上 removeAbandoned=true 相關釋放參數即可,我們這最終設定好的 context.xml 如下所示:

Shell
123456789101112 <Resource name="jdbc/smc"type="javax.sql.DataSource"username="user"password="password"driverClassName="oracle.jdbc.driver.OracleDriver"maxIdle="50"maxWait="2000"removeAbandoned="true"removeAbandonedTimeout="180"validationQuery="select * from dual "url="jdbc:oracle:thin:@192.168.7.98:1521:dw"maxActive="200"/>

資料庫連線設定參考:

Shell
1234567891011121314151617181920212223242526272829 #資料庫連線設定   jdbc.driverClassName=oracle.jdbc.driver.OracleDriverjdbcjdbc.url=jdbc:oracle:thin:@127.0.0.1:1521:DBSERVER   jdbc.username=user   jdbc.password=pass#<!-- 初始化連線 -->  dataSource.initialSize=10#<!-- 最大空閒連線 -->  dataSource.maxIdle=20#<!-- 最小空閒連線 -->  dataSource.minIdle=5#最大連線數量   dataSource.maxActive=50#是否在自動回收超時連線的時候列印連線的超時錯誤   dataSource.logAbandoned=true#是否自動回收超時連線   dataSource.removeAbandoned=true#超時時間(以秒數為單位)   dataSource.removeAbandonedTimeout=180#<!-- 超時等待時間以毫秒為單位 -->  dataSource.maxWait=1000

附上作者的原文說明:

在配置 DBCP 連線池時,主要難以理解的主要有:removeAbandoned 、logAbandoned、removeAbandonedTimeout、maxWait 這四個引數,設定了 rmoveAbandoned=true 那麼在 getNumActive()快要到 getMaxActive()的時候,系統會進行無效的 Connection 的回收,回收的 Connection 為 removeAbandonedTimeout(預設 300 秒)中設定的秒數後沒有使用的 Connection,啟用回收機制好像是 getNumActive()=getMaxActive()-2。

如果開啟"removeAbandoned",那麼連線在被認為洩露時可能被池回收. 這個機制在(getNumIdle() < 2) and (getNumActive() > getMaxActive() - 3)時被觸發.

舉例:當 maxActive=20, 活動連線為 18,空閒連線為 1 時可以觸發"removeAbandoned".但是活動連線只有在沒有被使用的時間超過"removeAbandonedTimeout"時才被刪除,預設 300 秒.在 resultset 中游歷不被計算為被使用.

logAbandoned=true 的話,將會在回收事件後,在 log 中打印出回收 Connection 的錯誤資訊,包括在哪個地方用了 Connection 卻忘記關閉了,在除錯的時候很有用。

在這裡私人建議 maxWait 的時間不要設得太長,maxWait 如果設定太長那麼客戶端會等待很久才激發回收事件。

通過仁兄的資料,加深了我對連線池引數的理解,非常感謝!特附上原文地址:DBCP 連線池配置引數說明及優化 ,以示尊重!

問題解決之後,就來瑪思閣簡單的記錄一下,希望能幫到有需要的同行朋友。