播放框架:数据库连接池关闭

Play Framework: DB Connection Pool Shut Down

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

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

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 属性。

关注这个很久了,非常感谢您的帮助!

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

hikaricp.minimumIdle = 0

HikariCP reference

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

查看您提供的日志,数据库连接池关闭的原因是应用程序(play)关闭。

Play documentation 中所述:

When you run the start command, Play forks a new JVM and runs the default Netty HTTP server. The standard output stream is redirected to the Play console, so you can monitor its status.

The server's process id is displayed at bootstrap and written to the RUNNING_PID file. To kill a running Play server, it is enough to send a SIGTERM to the process to properly shutdown the application.

If you type Ctrl+D, the Play console will quit, but the created server process will continue running in background. The forked JVM’s standard output stream is then closed, and logging can be read from the logs/application.log file.

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

Under desperately low memory conditions, the out-of-memory (OOM) killer kicks in and picks a process to kill using a set of heuristics which has evolved over time.

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

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

  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 启用 DEBUG 日志记录可能有助于进一步诊断数据库设置/应用程序的问题。

祝你好运!

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

我没有使用 nohup 命令启动我的应用程序。因此,该应用程序被 OS 终止并显示一条 SIGTERM 消息。

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

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

生活和学习。