【发布时间】:2014-01-16 15:10:05
【问题描述】:
我发现 JPA 有一些奇怪的行为。在某些情况下,我们遇到了错误
"Timed out waiting for a free available connection."
at com.jolbox.bonecp.DefaultConnectionStrategy.getConnectionInternal(DefaultConnectionStrategy.java:88) ~[bonecp.jar:na]
我做了简单的研究,发现了这个:
- Play2 使用带有 akka 的 actor 模型。
- Play2 使用 bonecp 作为数据库连接池。
-
对于处理@Transaction 请求,Play2 使用至少 2 个单独的参与者:
一个从池中获取连接并处理调用的参与者。
相关代码:
- https://github.com/playframework/playframework/blob/master/framework/src/play-java-jpa/src/main/java/play/db/jpa/TransactionalAction.java
- https://github.com/playframework/playframework/blob/master/framework/src/play-java-jpa/src/main/java/play/db/jpa/JPA.java#L180
- https://github.com/playframework/playframework/blob/master/framework/src/play/src/main/scala/play/core/j/JavaAction.scala#L61
提交或回滚事务的第二个参与者。此时已释放连接。
相关代码:
-
两个actor都从一个akka执行器和线程池执行。看:http://www.playframework.com/documentation/2.2.x/ThreadPools
默认有 24 个线程。
- 默认情况下,bonecp 池有 30 个连接可用。看:http://www.playframework.com/documentation/2.2.x/SettingsJDBC 的文档 和代码https://github.com/playframework/playframework/blob/master/framework/src/play-jdbc/src/main/scala/play/api/db/DB.scala#L372
假设我们有一个必须处理许多并发请求的高负载应用程序。在我的测试中,我遇到了 50 多个默认配置并发请求的问题。 您可以重复我的测试并使用非默认配置的仅 3 个并发请求来捕获此问题,如下所示:
play {
akka {
akka.loggers = ["akka.event.Logging$DefaultLogger", "akka.event.slf4j.Slf4jLogger"]
loglevel = DEBUG
actor {
default-dispatcher = {
fork-join-executor {
parallelism-factor = 1.0
parallelism-min = 1
parallelism-max = 1
}
}
}
}
}
...
db.default.minConnectionsPerPartition=2
db.default.maxConnectionsPerPartition=2
...
复杂性和处理时间对于这个测试来说并不重要。我的处理时间大约是 7 毫秒(解析参数 + 一次插入数据库)。您只需要发送比连接池大小更多的并发请求。 现在我写下我认为正在发生的事情。
- 许多参与者捕获线程和连接以处理请求。
-
许多参与者试图从池中获取连接。但是目前没有可用的免费连接(所有其他参与者都捕获了它们)。这个连接池基于 BlockingQueue。代码: https://github.com/wwadge/bonecp/blob/master/bonecp/src/main/java/com/jolbox/bonecp/DefaultConnectionStrategy.java#L82
所以当前线程在这一行被阻塞了一个超时(默认为一秒)。
- 如果某些线程被此 Actor 阻塞,则某些 Actor 无法使用此线程执行。
- 因此返回到连接池的连接更少,因为可以用更少的线程执行更少的参与者。
- 有时所有线程都会被阻塞。并且没有任何线程可用于将连接返回到池的执行参与者。
这看起来像死锁。
谁能给我一个建议,我该如何避免这个问题?
【问题讨论】:
标签: playframework playframework-2.0 akka