Play Framework:数据库连接池关闭

Posted

技术标签:

【中文标题】Play Framework:数据库连接池关闭【英文标题】:Play Framework: DB Connection Pool Shut Down 【发布时间】:2017-05-06 19:59:49 【问题描述】:

我有一个使用 HikariCP jdbc 连接池运行的 Play 应用程序。

该应用程序会在一段时间内正常运行,但在短时间内它会关闭连接池,这意味着我无法再使用该应用程序。

SBT 构建:

name := "virtual-betting"
version := "1.0"

lazy val root = (project in file(".")).enablePlugins(PlayJava).settings(javacOptions ++= Seq("-source", "1.8", "-target", "1.8"))

scalaVersion := "2.11.8"

libraryDependencies ++= Seq(
  javaJdbc,
  javaJpa,
  javaJpa.exclude("org.hibernate.javax.persistence", "hibernate-jpa-2.1-api"),
  "org.hibernate" % "hibernate-core" % "5.1.0.Final",
  "org.hibernate" % "hibernate-entitymanager" % "5.1.0.Final",
  "com.typesafe.play" % "play-java-jpa_2.11" % "2.5.3",
  "org.springframework" % "spring-context" % "4.2.4.RELEASE",
  "org.webjars" % "bootstrap" % "3.3.4",
  "mysql" % "mysql-connector-java" % "5.1.42",
  cache,
  javaWs,
  "org.jsoup" % "jsoup" % "1.7.2",
  "org.apache.commons" % "commons-email" % "1.4",
  "org.apache.cxf" % "cxf-rt-rs-client" % "3.1.6",
  "com.google.code.gson" % "gson" % "2.7",
  "com.squareup.okhttp3" % "okhttp" % "3.4.1"
)

fork in run := false


fork in run := true

application.conf:

## Database Connection Pool
# https://www.playframework.com/documentation/latest/SettingsJDBC
# ~~~~~
# Play doesn't require a JDBC database to run, but you can easily enable one.
#
# libraryDependencies += jdbc
#

play.db 
  # The combination of these two settings results in "db.default" as the
  # default JDBC pool:
  config = "db"
  default = "default"

  pool = "hikaricp"
  # Play uses HikariCP as the default connection pool.  You can override
  # settings by changing the prototype:

  prototype 
    pool = "hikaricp"

    # Sets a fixed JDBC connection pool size of 50
    hikaricp.minimumIdle = 0
    hikaricp.maximumPoolSize = 30
    hikaricp.connectionTimeout = 30000
    hikaricp.idleTimeout = 600000
    hikaricp.maxLifetime = 1800000
    hikaricp.leakDetectionThreshold = 5000
    hikaricp.connectionTestQuery = "SELECT 1"
    hikaricp.readOnly = false

    hikari.dataSourceClassName = com.mysql.jdbc.jdbc2.optional.MysqlDataSource
    # The database url
    #url = "jdbc:mysql://localhost:3306/madduxsp_sportsbook?autoReconnect=true&useUnicode=true&characterEncoding=UTF-8"

    registerMBeans = true
    poolName = "sportsbook_pool"
  


db.default.driver=com.mysql.jdbc.Driver
db.default.url="jdbc:mysql://localhost:3306/madduxsp_sportsbook_new?autoReconnect=true&useUnicode=true&characterEncoding=UTF-8"
db.default.username=root
db.default.password=mypassword
db.default.jndiName=DefaultDS
jpa.default=defaultPersistenceUnit

application.secret="mysecret"

spring.context.location=application-context.xml

我已经编写了一些代码来保持数据库连接处于活动状态,这可以正常工作,以防它因不活动而关闭。

我的 DbKeepAliveService:

package services;

import play.Logger;
import play.db.jpa.JPAApi;
import util.DbKeepAliveTask;

import javax.inject.Inject;
import javax.inject.Singleton;
import java.util.Timer;

@Singleton
public class DbKeepAliveService 

    private final JPAApi jpa;

    @Inject
    public DbKeepAliveService(JPAApi jpa) 
        this.jpa = jpa;

        DbKeepAliveTask dbKeepAliveTask = new DbKeepAliveTask(jpa);
        Logger.info("Application has started");

        Timer timer = new Timer("dbKeepAlive", true);
        timer.schedule(dbKeepAliveTask, 0, 1200000);
    

除非这不起作用。这是我的日志:

2017-05-06 06:12:15,010 [INFO] from application in dbKeepAlive - Keeping database connection alive...
2017-05-06 06:32:15,010 [INFO] from application in dbKeepAlive - Keeping database connection alive...
2017-05-06 06:52:15,010 [INFO] from application in dbKeepAlive - Keeping database connection alive...
2017-05-06 06:58:35,894 [INFO] from application in Thread-8 - Application shutdown...
2017-05-06 06:58:36,054 [INFO] from application in Thread-8 - Shutting down connection pool.

有没有人知道为什么它可能会不断关闭数据库连接池?我怀疑这与我的配置有关,但老实说我不能确定。

我还读到这可能与未在生产模式下运行应用程序有关,但我已经设置了秘密。

我使用以下命令运行应用程序:

./bin/virtual-betting -Dconfig.file=conf/production.conf -Dplay.crypto.secret="mysecret" &

conf/production.conf 文件中设置play.crypto.secret 属性。

关注此问题已久,非常感谢您的帮助!

【问题讨论】:

【参考方案1】:

查看您提供的日志表明数据库连接池关闭的原因是因为应用程序(播放)已关闭。

如Play documentation中所述:

当您运行 start 命令时,Play 会创建一个新的 JVM 并运行默认的 Netty HTTP 服务器。标准输出流被重定向到 Play 控制台,因此您可以监控其状态。

服务器的进程 ID 在引导时显示并写入 RUNNING_PID 文件。要终止正在运行的 Play 服务器,只需向进程发送 SIGTERM 以正确关闭应用程序。

如果您按 Ctrl+D,Play 控制台将退出,但创建的服务器进程将继续在后台运行。然后关闭分叉的 JVM 的标准输出流,并且可以从 logs/application.log 文件中读取日志记录。

因此,可能是进程收到了 SIGTERM 信号,Play 应用程序以 play run 而不是 play start 启动,并且有人在控制台或服务器上使用了 Ctrl+D正在杀死该进程,因为它的内存不足,这可能表示或可能不表示您的应用程序中存在内存泄漏,请参阅OOM killer:

在内存极低的情况下,内存不足 (OOM) 杀手会启动并使用一组随时间演变的启发式方法来选择要杀死的进程。

我建议您分析您的应用程序/监控服务器内存(您还可以检查服务器日志以查看内核是否已终止任何进程)。

如果您能够扩展 HikariCPModule 并覆盖 close 方法,您可以添加一个记录器调用来打印当前线程堆栈跟踪并验证实际调用 close 的内容,例如。关闭挂钩或其他东西。

  override def close(dataSource: DataSource) = 
    Logger.info("Shutting down connection pool.")
    Thread.dumpStack()
    dataSource match 
      case ds: HikariDataSource => ds.close()
      case _ => sys.error("Unable to close data source: not a HikariDataSource")
    

为“com.zaxxer.hikari”和 Play 启用调试日志记录可能有助于进一步诊断数据库设置/应用程序的问题。

祝你好运!

【讨论】:

【参考方案2】:

所以我不久前发现了我的问题所在。真的很蠢。

我没有使用nohup 命令启动我的应用程序。结果,应用程序被操作系统终止,并带有 SIGTERM 消息。

这与我的应用完全无关......

所以基本上,nohup 将输出输出到 dev > null

生活和学习。

【讨论】:

【参考方案3】:

您可能希望删除 minimumIdle 配置,因为建议 HikariCP 将其设置为默认值

hikaricp.minimumIdle = 0

HikariCP reference

还要检查 30 的连接池大小是否足够好。

【讨论】:

感谢@jayant,到目前为止我不得不说这是一个非常令人沮丧的过程。我会看看两者 - 谢谢! 不幸的是@jayant 这似乎不是问题。我今天早上来看它,它又失败了。

以上是关于Play Framework:数据库连接池关闭的主要内容,如果未能解决你的问题,请参考以下文章

Play Framework 1.3中如何通过application.conf和c3p0.properties配置连接池?

Play Framework:“连接太多”数据库错误

Play framework 2.1:连接数据库有时会崩溃。如何确保它在产品中?

如何在 Play Framework v2 中指定自定义数据库连接参数以进行测试?

使用 play framework v1.5 连接 db postgresql 时出错

HikariCP - Play Framework 1.2.7 JMX MBean 监控