連接池未關閉問題的發現與解決

    最近項目上線,但是大下午的客服反應項目登錄頁面很慢,SA發現後立馬重啓後項目訪問速度恢復。  排查問題時,發現nginx的頁面訪問速度都是在十秒左右,有部分二十秒,這個時間很奇怪。日誌顯示,項目並沒有什麼特殊的錯誤異常。跟據經驗立馬確認了下連接池的maxwait時間爲10000,與是百分之九十肯定是項目中有連接池未關閉的操作。

    但是此項目上線已經幾天,說明此未關閉的地方很隱蔽,另外項目比較大,大家一起查了下DAO的代碼,也沒有什麼頭緒,因爲正常所有的DAO操作在finally都有相關close操作,對於一些需要保持連接的操作,通過keepalive,也進行了急時關閉,所以要具體問題在哪很麻煩。

    另外重啓後,通過show processlist,發現此應用的連接數每天都會有一些增加,雖然不是很明顯,但是每天有些增加,更堅定了我的判斷。

   由於項目是在原來老有項目中基礎上開發,連接池使用了原有的tomcat自帶的dbcp,其配製是通過JNDI配製。記得連接池是有自動釋放連接的配製,通過google,找到資料如下:

   設置數據源的removeAbandoned="true",removeAbandonedTimeout="60",logAbandoned="true"幾個屬性就可以了。 DBCP會自動把超過timeout時間仍未關閉的連接強制關閉,並且打出異常信息(包含打開連接的代碼位置) ,其中第一參數,打開自動釋放未被使用的連接,而第二參數爲多長時間未被使用的連接,第三個參數打印dbcp自動關閉時,輸出的log4j日誌。(這些參數有些地方需要說明:1.removeAbandonedTimeout一定需要估量自己項目中某個操作最長使用的時間,其中此參數爲秒。2.對於數據庫連接池還是我們自己控制關閉更好些,而使用上面配製是爲了幫忙找出未關閉的地方在什麼地方。修正後,可以關閉這些配製。3.log4j的日誌配製級別一定需要在debug以上日誌才能輸出)

    修改以上配製後,服務器做了一次更新。前四天很正常,都沒有錯誤的日誌。在我以爲自己判斷失誤的情況下,今天早上來一到公司,習慣性的掃描起日誌來,突然發現了一堆

org.apache.tomcat.dbcp.dbcp.AbandonedTrace$AbandonedObjectException: DBCP object created 2011-07-29 08:30:25 by the following code was never closed: 讓我異常興奮。然後定位到詳細的日誌,定位到了代碼。

    查看代碼後,這個BUG讓我們很無語。一個同事把一些本是service判斷屬性是否爲null的邏輯代碼,放到了DAO裏面,而此判斷又是在DAO裏面的try{}finally的外面,而DB的構造是在此DAO的外層,所以構造DB實例時,當出現此屬性爲NULL的情況時,會直接返回。這樣跟據沒有執行try{}finally裏面的代碼,即不存在close了。而此操作又是一個小權限的用戶下,且此權限下某個特定邏輯時纔會觸發。這也是爲什麼幾天都沒有觸發的原因。

   到此,問題得到解決,把邏輯代碼提出到外層service後,問題就得到解決了。通過此次問題的解決,讓我考慮的東西又多了些。代碼的review,service與dao的嚴格區分,DAO連接關閉的處理等等

    問題解決了很開心,下面附一下默認DBCP連接池的配製參數的說明:

   maxActive :連接池中可同時連接的最大的連接數(默認值爲8,調整爲20,高峯單機器在20併發左右,自己根據應用場景定)
   maxIdle:連接池中最大的空閒的連接數,超過的空閒連接將被釋放,如果設置爲負數表示不限制(默認爲8個,maxIdle不能設置太小,因爲假如在高負載的情況下,連接的打開時間比關閉的時間快,會引起連接池中idle的個數 上升超過maxIdle,而造成頻繁的連接銷燬和創建,類似於jvm參數中的Xmx設置)
    minIdle:連接池中最小的空閒的連接數,低於這個數量會被創建新的連接(默認爲0,調整爲5,該參數越接近maxIdle,性能越好,因爲連接的創建和銷燬,都是需要消耗資源的;但是不能太大,因爲在機器很空閒的時候,也會創建低於 minidle個數的連接,類似於jvm參數中的Xmn設置)
    maxWait  :最大等待時間,當沒有可用連接時,連接池等待連接釋放的最大時間,超過該時間限制會拋出異常,如果設置-1表示無限等待(默認爲無限,調整爲60000ms,避免因線程池不夠用,而導致請求被無限制掛起)
    poolPreparedStatements:開啓池的prepared(默認是false,未調整,經過測試,開啓後的性能沒有關閉的好。)
    maxOpenPreparedStatements:開啓池的prepared 後的同時最大連接數(默認無限制,同上,未配置)
    minEvictableIdleTimeMillis  :連接池中連接,在時間段內一直空閒, 被逐出連接池的時(默認爲30分鐘,可以適當做調整,需要和後端服務端的策略配置相關)
    removeAbandonedTimeout  :超過時間限制,回收沒有用(廢棄)的連接(默認爲 300秒,調整爲180)
    removeAbandoned  :超過removeAbandonedTimeout時間後,是否進 行沒用連接(廢棄)的回收(默認爲false,調整爲true)

    

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