weblogic10.3 探测连接池泄漏故障解决
最近在一次客户服务的过程中遇到weblogic10.3探测连接池泄漏的现象,本来笔者以为是weblogic本身出现的连接池泄漏造成的,因为在weblogic7.x存在连接池泄漏的现象还是很严重的.这也是笔者首次遇到weblogic10.3探测到数据库连接池泄漏.
当时主要场景是这样的:
1,是客户当时的业务高峰期.
2,客户做了WLS集群,集群中有两台server一台connectionPool连接状态很正常且使用的数目很少,一台
server的connectionPool出现overload状态,connection已经被全部使用。
3,集群的算法选择的是均衡分发.
4,客户当时的配置信息是:
max thread value:50
max connection value:25
当时处理的措施是通过WLST收集集群中两台server的threaddump信息.下面是基于当日sever上收集
的threaddump信息来分析的.(出于保护客户信息的需要部分代码内容需要用XX表示,希望谅解).
从当时出故障的一个server做的 thread dump 看共有50个线程在执行,其中有4个线程(线程号分别是
30,31,33,49)在对业务操作,这4个线程在尝试从数据库连接池中获取可用连接
(ResourcePoolImpl.reserveResourceInternal),但是一直处于在等待(object.wait)数据库连接池中
空闲连接的状态. 那么按道理来说,我们至少有25个物理连接connection是可用的(不计算池的复用
技术,我们的连接池中最大值是25).排除4个和我们业务操作有联系的线程还应该有21个可用连接的.
但是从当时的thread dump信息来看并没有其余的21个connection被我们当前执行的线程使用.那么肯
定有connection泄漏出现和我们业务有联系的详细线程信息分别是:
30号线程信息(其他的31,33,49号线程信息类似)
"ExecuteThread: '30' for queue: 'default'" waiting for lock
weblogic.jdbc.common.internal.ConnectionPool@6b896b89TIMED_WAITING native
java.lang.Object.wait(Native Method)
java.lang.Object.wait(Object.java:196)
weblogic.common.resourcepool.ResourcePoolImpl.reserveResourceInternal(ResourcePoolImpl.java:460)
weblogic.common.resourcepool.ResourcePoolImpl.reserveResource(ResourcePoolImpl.java:302)
weblogic.common.resourcepool.ResourcePoolImpl.reserveResource(ResourcePoolImpl.java:292)
weblogic.jdbc.common.internal.ConnectionPool.reserve(ConnectionPool.java:425)
weblogic.jdbc.common.internal.ConnectionPool.reserve(ConnectionPool.java:316)
weblogic.jdbc.common.internal.ConnectionPoolManager.reserve(ConnectionPoolManager.java:93)
weblogic.jdbc.common.internal.ConnectionPoolManager.reserve(ConnectionPoolManager.java:106)
weblogic.jdbc.pool.Driver.connect(Driver.java:149)
weblogic.jdbc.jts.Driver.getNonTxConnection(Driver.java:642)
weblogic.jdbc.jts.Driver.connect(Driver.java:124)
weblogic.jdbc.common.internal.RmiDataSource.getConnection(RmiDataSource.java:338)
com.xxxx.xxxxxxx.reference.DBManager.open(DBManager.java:63)
com.xxxx.accfee.bl.facade.BLPrpDbroadcastHeadFacade.findByConditions(BLPrpDbroadcastHeadFacade.java:26)
jsp_servlet._common.__login._jspService(__login.java:199)
weblogic.servlet.jsp.JspBase.service(JspBase.java:34)
weblogic.servlet.internal.StubSecurityHelper$ServletServiceAction.run(StubSecurityHelper.java:227)
weblogic.servlet.internal.StubSecurityHelper.invokeServlet(StubSecurityHelper.java:125)
weblogic.servlet.internal.ServletStubImpl.execute(ServletStubImpl.java:292)
weblogic.servlet.internal.ServletStubImpl.execute(ServletStubImpl.java:175)
weblogic.servlet.internal.WebAppServletContext$ServletInvocationAction.run
(WebAppServletContext.java:3498)
weblogic.security.acl.internal.AuthenticatedSubject.doAs(AuthenticatedSubject.java:321)
weblogic.security.service.SecurityManager.runAs(Unknown Source)
weblogic.servlet.internal.WebAppServletContext.securedExecute(WebAppServletContext.java:2180)
weblogic.servlet.internal.WebAppServletContext.execute(WebAppServletContext.java:2086)
weblogic.servlet.internal.ServletRequestImpl.run(ServletRequestImpl.java:1406)
weblogic.work.ExecuteRequestAdapter.execute(ExecuteRequestAdapter.java:21)
weblogic.kernel.ExecuteThread.execute(ExecuteThread.java:145)
weblogic.kernel.ExecuteThread.run(ExecuteThread.java:117)
进一步研究当前服务器 thread dump,我们可以发现,其它46个执行线程(总的是50个线程,上面的4
个是和我们的业务逻辑发生操作的),全都是空闲状态,及在等新的客户请求。所以显然是这25个连
接(包含上面等待的4个连接)都泄漏出去了。应用必须在使用完连接后,主动调用close(把close 放
在finally语句里面).建议关于连接池关闭的范式按照jvm规范范式去书写.JVM范式中对connection打
开的资源要每一层都用独立的
try{}
catch()
finally{}
的操作结构去关闭资源.
参考示例代码:
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
publicfinalclass ConnTest {
privatestatic String url = "jdbc:mysql://localhost:3306/jdbc";
privatestatic String user = "root";
privatestatic String password = "";
private ConnTest() {}
static {
try {
Class.forName("com.mysql.jdbc.Driver");
} catch (ClassNotFoundException e) {
thrownew ExceptionInInitializerError(e);
}
}
publicstatic Connection getConnection() throws SQLException {
return DriverManager.getConnection(url, user, password);
}
publicstaticvoid close(ResultSet rs, Statement st, Connection conn) {
try {
if (rs != null)
rs.close();
} catch (SQLException e) {
e.printStackTrace();
} finally {
try {
if (st != null)
st.close();
} catch (SQLException e) {
e.printStackTrace();
} finally {
if (conn != null)
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
}
其余的46个线程的详细信息都和25号线程信息类似如下:
"ExecuteThread: '25' for queue: 'default'" waiting for lock
weblogic.kernel.ServerExecuteThread@2d852d85 WAITING native
java.lang.Object.wait(Native Method)
java.lang.Object.wait(Object.java:167)
weblogic.kernel.ExecuteThread.waitForRequest(ExecuteThread.java:91)
weblogic.kernel.ExecuteThread.run(ExecuteThread.java:115)
"ExecuteThread: '26' for queue: 'default'" waiting for lock
weblogic.kernel.ServerExecuteThread@2f652f65 WAITING native
java.lang.Object.wait(Native Method)
java.lang.Object.wait(Object.java:167)
weblogic.kernel.ExecuteThread.waitForRequest(ExecuteThread.jav:91)
weblogic.kernel.ExecuteThread.run(ExecuteThread.java:115)
"ExecuteThread: '27' for queue: 'default'" waiting for lock
weblogic.kernel.ServerExecuteThread@31453145 WAITING native
java.lang.Object.wait(Native Method)
java.lang.Object.wait(Object.java:167)
weblogic.kernel.ExecuteThread.waitForRequest(ExecuteThread.ja:91)
weblogic.kernel.ExecuteThread.run(ExecuteThread.java:115)
"ExecuteThread: '28' for queue: 'default'" waiting for lock
weblogic.kernel.ServerExecuteThread@33253325 WAITING native
java.lang.Object.wait(Native Method)
java.lang.Object.wait(Object.java:167)
weblogic.kernel.ExecuteThread.waitForRequest(ExecuteThread.java:91)
weblogic.kernel.ExecuteThread.run(ExecuteThread.java:115)
从WebLogic层面,建议可以在console中将连接池的inactive time out 的值给设上适当的值来以缓解此问题.