gpt4 book ai didi

java - 读取线程转储以调试耗尽的数据库连接池

转载 作者:行者123 更新时间:2023-11-29 03:35:04 26 4
gpt4 key购买 nike

我有一个由 jetty + mysql 提供服务的网络应用程序。我遇到了一个问题,我的数据库连接池耗尽,所有线程都开始阻塞等待连接。我试过两个数据库连接池库:(1)bonecp(2)hikari。两者在我的应用程序中都表现出相同的行为。

当我看到这种状态时,我已经进行了几次线程转储,并且所有被阻塞的线程都处于这种状态(没有选择 bonecp,我确定它现在是我这边的东西):

"qtp1218743501-131" prio=10 tid=0x00007fb858295800 nid=0x669b waiting on condition [0x00007fb8cd5d3000]
java.lang.Thread.State: TIMED_WAITING (parking)
at sun.misc.Unsafe.park(Native Method)
- parking to wait for <0x0000000763f42d20> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)
at java.util.concurrent.locks.LockSupport.parkNanos(LockSupport.java:226)
at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.awaitNanos(AbstractQueuedSynchronizer.java:2082)
at java.util.concurrent.LinkedBlockingQueue.poll(LinkedBlockingQueue.java:467)
at com.jolbox.bonecp.DefaultConnectionStrategy.getConnectionInternal(DefaultConnectionStrategy.java:82)
at com.jolbox.bonecp.AbstractConnectionStrategy.getConnection(AbstractConnectionStrategy.java:90)
at com.jolbox.bonecp.BoneCP.getConnection(BoneCP.java:553)
at com.me.Foo.start(Foo.java:30)
...

我不确定从这里到哪里去。我在想我会在线程转储中看到一些堆栈跟踪,我的代码在这些线程转储中被困在做一些冗长的操作,而不是等待连接。例如,如果我的代码如下所示:

public class Foo {
public void start() {
Connection conn = threadPool.getConnection();
work(conn);
conn.close();
}

public void work(Connection conn) {
.. something lengthy like scan every row in the database etc ..
}
}

我希望上面的线程之一有一个堆栈跟踪,显示它在 work() 方法中工作:

...
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()

任何关于如何继续调试的想法都会很棒。

一些其他背景:该应用程序正常运行了大约 45 分钟,内存和线程转储没有任何异常。然后条件被触发,线程数激增。我开始认为这可能是应用程序尝试执行的 sql 语句的某种组合,这些语句变成了 mysql 端的某种锁,但我再次希望上面堆栈跟踪中的一些线程向我展示它们是在那部分代码中。

线程转储是使用 visualvm 获取的。

谢谢

最佳答案

利用连接池的配置选项(参见 BoneCPConfig/HikariCPConfig )。首先,设置连接超时(HikariCP connectionTimeout)和泄漏检测超时(HikariCP leakDetectionThreshold,我在BoneCP中找不到对应的)。可能有更多配置选项可以在出现问题时转储堆栈跟踪。

我的猜测是您的应用程序并不总是返回到池的连接,并且在 45 分钟后池中不再有连接(因此永远阻止尝试从池中获取连接)。将连接视为打开/关闭文件,即始终使用 try/finally:

public void start() {

Connection conn = null;
try {
work(conn = dbPool.getConnection());
} finally {
if (conn != null) {
conn.close();
}
}
}

最后,两个连接池都有允许JMX 监控 的选项。您可以使用它来监视池中的异常行为。

关于java - 读取线程转储以调试耗尽的数据库连接池,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23452177/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com