常見故障之八:JDBC Connection Pools

fiona8953發表於2015-05-06
WebLogic Server中,資料庫連線池是一個經常出問題的地方。下面就總結一下出問題的原因和解決辦法。

1.資料庫連線洩漏
此類問題一般都是由於開發人員沒有正確關閉資料庫連線造成的。比如,使用完Connection後,沒有呼叫Connection.close()方法。

1.1. 診斷方法
在Console中,找到Connection Pools Tab 和Diagnostics,設定以下屬性(不同版本可能略有區別)
Enable Connection Leak Profiling 啟用連線池洩漏的監控。
Enable Connection Profiling 啟用連線池監控。
Inactive Connection Timeout 100 表示100秒後強制回收無效連線。預設0,表示使用完才釋放回連線池。
無需重啟,檢視server的log,查詢“A JDBC pool connection leak was detected”,如果有,看看是哪個類引起的。
下面是一個資料庫連線洩漏的例子:
A JDBC pool connection leak was detected.
A connection leak occurs when a connection obtained from the pool was not closed explicitly by calling close() and then was disposed by the garbage collector and returned to the connection pool.
The following stack trace at create shows where the leaked connection was created.
Stack trace at connection create:

at weblogic.jdbc.wrapper.JTAConnection.init(JTAConnection.java:90)
at weblogic.jdbc.jta.DataSource.getConnection(DataSource.java:468)
at weblogic.jdbc.jta.DataSource.connect(DataSource.java:410)
at weblogic.jdbc.common.internal.RmiDataSource.getConnection(RmiDataSource.java:344)
at troubleshooting.servlets.JdbcConnections.service(JdbcConnections.java:97)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:853)
at weblogic.servlet.internal.ServletStubImpl$ServletInvocationAction.run(ServletStubImpl.java:1077)
at weblogic.servlet.internal.ServletStubImpl.invokeServlet(ServletStubImpl.java:465)
at weblogic.servlet.internal.ServletStubImpl.invokeServlet(ServletStubImpl.java:348)
at weblogic.servlet.internal.WebAppServletContext$ServletInvocationAction.run(WebAppServletContext.java:7047)
at weblogic.security.acl.internal.AuthenticatedSubject.doAs(AuthenticatedSubject.java:321)
at weblogic.security.service.SecurityManager.runAs(SecurityManager.java:121)
at weblogic.servlet.internal.WebAppServletContext.invokeServlet(WebAppServletContext.java:3902)
at weblogic.servlet.internal.ServletRequestImpl.execute(ServletRequestImpl.java:2773)
at weblogic.kernel.ExecuteThread.execute(ExecuteThread.java:224)
at weblogic.kernel.ExecuteThread.run(ExecuteThread.java:183)

問題解決後,把三個屬性設定回先前的值。

1.2. 解決方法
正確的關閉資料庫連線。具體程式碼如下:
Connection conn = null;
ResultSet rs = null;
preparedStatement pss = null;
try {
conn = dataSource.getConnection(USERID,pASSWORD);
pss = conn.prepareStatement("SELECT SAVESERIALZEDDATA FROM SESSION.pINGSESSION3DATA WHERE SESSIONKEY = ?");
pss.setString(1,sessionKey);
rs = pss.executeQuery();
pss.close();
} catch (Throwable t) {
// 錯誤處理
} finally {
try {
if (conn != null) conn.close();
} catch (Exception e){}
}

2.資料庫連線不夠用
導致資料庫連線不夠用的原因主要有:
(1)某些程式佔用connection時間過長,如果多個使用者同時使用這些程式,則會導致連線不夠用。
(2)執行緒死鎖,無法釋放connection。

2.1. 診斷方法
(1)監控引數:Waiting For Connection High Count
[domain_name]-> Enviroment -> Servers -> [Server] -> Monitoring -> JDBC檢視引數:Waiting For Connection High Count
如果沒有此引數,手工新增進來,該參數列示在沒有可用連線的情況下,應用程式等待連線的最大個數。
調整後的連線池最大值 = 調整前的連線池最大值 + Waiting For Connection High Count。
一般來說,資料庫連線池的大小與最佳併發使用者數相當。

(2)在Server Log中,明確丟擲下列異常:
java.sql.SQLException: Internal error: Cannot obtain XAConnection weblogic.common.resourcepool.ResourceLimitException: No resources currently available in pool BankConnectionPool to allocate to applications, please increase the size of the pool and retry..
at weblogic.jdbc.jta.DataSource.refreshXAConnAndEnlist(DataSource.java:1493)
at weblogic.jdbc.jta.DataSource.getConnection(DataSource.java:455)
at weblogic.jdbc.jta.DataSource.connect(DataSource.java:410)
at weblogic.jdbc.common.internal.RmiDataSource.getConnection(RmiDataSource.java:344)
at troubleshooting.servlets.JdbcConnections.service(JdbcConnections.java:80)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:853)
at weblogic.servlet.internal.ServletStubImpl$ServletInvocationAction.run(ServletStubImpl.java:1077)
at weblogic.servlet.internal.ServletStubImpl.invokeServlet(ServletStubImpl.java:465)
at weblogic.servlet.internal.ServletStubImpl.invokeServlet(ServletStubImpl.java:348)
at weblogic.servlet.internal.WebAppServletContext$ServletInvocationAction.run(WebAppServletContext.java:7047)
at weblogic.security.acl.internal.AuthenticatedSubject.doAs(AuthenticatedSubject.java:321)
at weblogic.security.service.SecurityManager.runAs(SecurityManager.java:121)
at weblogic.servlet.internal.WebAppServletContext.invokeServlet(WebAppServletContext.java:3902)
at weblogic.servlet.internal.ServletRequestImpl.execute(ServletRequestImpl.java:2773)
at weblogic.kernel.ExecuteThread.execute(ExecuteThread.java:224)
at weblogic.kernel.ExecuteThread.run(ExecuteThread.java:183)

如果此時觀察connection的監控,會發現所有connection 都是Active,而且還有大量請求等待connection。

2.2. 解決方法
(1)提高Maximum Capacity數量,該值一般略大於峰值情況下的資料庫連線數。
Services > JDBC > Connection Pools > BankConnectionPool > Configuration > Connections
(2)重點檢查synchronize程式碼段和涉及資料庫鎖的程式碼。如果有必要,可以檢視thread dump,看看執行緒在忙什麼和等什麼。

3.資料庫連線使用超時
此類問題一般是由於某些資料庫操作時間比較長,超過了Inactive connection timeout的設定。

3.1. 診斷方法
在Server Log中,明確有下列提示,並且在提示後丟擲應用異常:
Forcibly releasing inactive resource "weblogic.jdbc.common.internal.ConnectionEnv@132967d" back into the pool "BankConnectionPool".
這裡無法列出應用異常,因為每個應用都不一樣,不過很有可能會丟擲空指標異常,因為Connection被強制放回池中了,繼續使用一個空物件會丟擲該異常。

3.2. 解決方法
在高階引數中,提高Inactive connection timeout數量。
Services > JDBC > Connection Pools > BankConnectionPool > Configuration > Connections

4.事務超時
此類問題一般是由於某些資料庫操作時間比較長,超過了JTA Timeout Seconds的設定。

4.1. 診斷方法
在Server Log中,明確丟擲異常:
weblogic.transaction.internal.TimedOutException: Transaction timed out after 300 seconds

4.2. 解決方法
提高Services > JTA Configuration > Timeout Seconds數量。
注意,這個引數應該小於Inactive connection timeout的值,因為事務必須在連線超時前完成。

如果想分析究竟是哪些SQL語句導致事務超時,可以開啟日誌AdminServer > Logging > JDBC,選中Enable JDBC Logging,並設定JDBC Log File Name。

參考文獻:
1. http://www.ibm.com/developerworks/cn/websphere/library/bestpractices/closing_and_releasing_jdbc_resources.html
2. http://blog.csdn.net/esky2000/archive/2008/07/22/2689929.aspx
3.

Refer to:http://maping930883.blogspot.hk/2009/03/wls040jdbc-connection.html

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/26477398/viewspace-1626587/,如需轉載,請註明出處,否則將追究法律責任。

相關文章