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

2021-09-02 08:40:47 字數 2442 閱讀 7100

最近專案上線,但是大下午的客服反應專案登入頁面很慢,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)

連線池關閉的疑問

請看 oracleconnectioncacheimpl connpool new oracleconnectioncacheimpl connpool.seturl url connpool.setuser username connpool.setpassword password connpo...

使用DBCP連線池檢測未關閉的資料庫連線

我一直使用dbcp連線池,效果還不錯。最近因為朋友的乙個j2ee應用一上連線池,很快就會報connection pool exhausted的錯誤,所以 特地研究了一下如何自動檢測未關閉的資料庫連線的技術。研究了tomcat文件中datasource一章,發現有專門的preventing db co...

連線池與使用Tomcat的連線池

what is connection pool?看圖 1 存放connection物件的容器 2 減少連線資料庫的開銷 3 程式請求連線時,在connection pool中取連線 4 連線使用完後,放回connection pool,不釋放 5 connection pool對連線進行管理 計數 ...