Java 读取线程转储以调试耗尽的数据库连接池
我有一个由jetty+mysql提供服务的web应用程序。我遇到了一个问题,数据库连接池耗尽,所有线程开始阻塞等待连接。我尝试了两个数据库连接池库:(1)bonecp(2)hikari。两者在我的应用程序中表现出相同的行为 当我看到这种状态时,我已经做了几次线程转储,所有被阻止的线程都处于这种状态(不是选择bonecp,我确信这是我的问题): 我希望上面的一个线程有一个堆栈跟踪,显示它在work()方法中工作: 但他们只是在等待连接:Java 读取线程转储以调试耗尽的数据库连接池,java,mysql,connection-pooling,Java,Mysql,Connection Pooling,我有一个由jetty+mysql提供服务的web应用程序。我遇到了一个问题,数据库连接池耗尽,所有线程开始阻塞等待连接。我尝试了两个数据库连接池库:(1)bonecp(2)hikari。两者在我的应用程序中表现出相同的行为 当我看到这种状态时,我已经做了几次线程转储,所有被阻止的线程都处于这种状态(不是选择bonecp,我确信这是我的问题): 我希望上面的一个线程有一个堆栈跟踪,显示它在work()方法中工作: 但他们只是在等待连接: ... at com.jolbox.bonecp.BoneC
...
at com.jolbox.bonecp.BoneCP.getConnection() // ?
at com.me.mycode.Foo.work()
at com.me.mycode.Foo.start()
任何关于如何继续调试的想法都会很好
其他一些背景:该应用程序正常运行约45分钟,内存和线程转储没有显示任何异常。然后,该条件被触发,线程数将增加。我开始想,这可能是应用程序试图执行的sql语句的某种组合,在mysql端会变成某种锁,但我还是希望上面堆栈跟踪中的一些线程向我显示它们在代码的这一部分
线程转储是使用visualvm进行的
谢谢我怀疑整个设计 如果在多线程netIO中有一个等待块,则需要更好的连接实现
我建议您查看非阻塞IO(Java.nio,channels包),或将锁粒度化。利用连接池的配置选项(请参阅/)。首先,设置连接超时(HikariCP
connectionTimeout
)和泄漏检测超时(HikariCPleakDetectionThreshold
,我在BoneCP中找不到对应项)。可能会有更多的配置选项,用于在出现问题时转储堆栈跟踪
我的猜测是,您的应用程序并不总是返回到池的连接,45分钟后池中就不再有连接了(因此会永远阻止尝试从池中获取连接)。将连接视为打开/关闭文件,即始终使用try/finally:
public void start() {
Connection conn = null;
try {
work(conn = dbPool.getConnection());
} finally {
if (conn != null) {
conn.close();
}
}
}
最后,两个连接池都有允许
JMX监视的选项。您可以使用它来监视池中的奇怪行为。是的,我为bonecp启用了日志记录,它向我指出了我的连接泄漏:Ddid您是否使用“资源试用”尝试过连接逻辑?
...
at com.me.mycode.Foo.work()
at com.me.mycode.Foo.start()
...
at com.jolbox.bonecp.BoneCP.getConnection() // ?
at com.me.mycode.Foo.work()
at com.me.mycode.Foo.start()
public void start() {
Connection conn = null;
try {
work(conn = dbPool.getConnection());
} finally {
if (conn != null) {
conn.close();
}
}
}