HikariCP尝试资源连接泄漏

时间:2018-08-11 01:42:40

标签: java sql redis mariadb hikaricp

我正在做一些需要从MariaDB(使用HikariCP)提取数据,然后通过Redis发送数据的事情。最终,当我尝试从数据库中提取数据时,连接将开始泄漏。这只是随着时间的流逝而突然发生。

以下是泄漏开始发生时的完整日志:https://hastebin.com/sekiximehe.makefile

以下是一些调试信息:

21:04:40 [INFO] 21:04:40.680 [HikariPool-1 housekeeper] DEBUG com.zaxxer.hikari.pool.HikariPool - HikariPool-1 - Before cleanup stats (total=6, active=2, idle=4, waiting=0)

21:04:40 [INFO] 21:04:40.680 [HikariPool-1 housekeeper] DEBUG com.zaxxer.hikari.pool.HikariPool - HikariPool-1 - After cleanup  stats (total=6, active=2, idle=4, waiting=0)

21:04:40 [INFO] 21:04:40.682 [HikariPool-1 connection adder] DEBUG com.zaxxer.hikari.pool.HikariPool - HikariPool-1 - Added connection org.mariadb.jdbc.MariaDbConnection@4b7a5e97

21:04:40 [INFO] 21:04:40.682 [HikariPool-1 connection adder] DEBUG com.zaxxer.hikari.pool.HikariPool - HikariPool-1 - After adding stats (total=7, active=2, idle=5, waiting=0)

21:05:05 [INFO] 21:05:05.323 [HikariPool-1 housekeeper] WARN  com.zaxxer.hikari.pool.ProxyLeakTask - Connection leak detection triggered for org.mariadb.jdbc.MariaDbConnection@52ede989 on thread Thread-272, stack trace follows
java.lang.Exception: Apparent connection leak detected
        at com.zaxxer.hikari.HikariDataSource.getConnection(HikariDataSource.java:123)
        at us.survivewith.bungee.database.FetchPlayerInfo.run(FetchPlayerInfo.java:29)
        at java.lang.Thread.run(Thread.java:748)

21:05:10 [INFO] 21:05:10.681 [HikariPool-1 housekeeper] DEBUG com.zaxxer.hikari.pool.HikariPool - HikariPool-1 - Before cleanup stats (total=7, active=2, idle=5, waiting=0)

21:05:10 [INFO] 21:05:10.681 [HikariPool-1 housekeeper] DEBUG com.zaxxer.hikari.pool.HikariPool - HikariPool-1 - After cleanup  stats (total=7, active=2, idle=5, waiting=0)

21:05:39 [INFO] 21:05:39.352 [HikariPool-1 housekeeper] WARN  com.zaxxer.hikari.pool.ProxyLeakTask - Connection leak detection triggered for org.mariadb.jdbc.MariaDbConnection@3cba7850 on thread Thread-274, stack trace follows
java.lang.Exception: Apparent connection leak detected
        at com.zaxxer.hikari.HikariDataSource.getConnection(HikariDataSource.java:123)
        at us.survivewith.bungee.database.FetchPlayerInfo.run(FetchPlayerInfo.java:29)
        at java.lang.Thread.run(Thread.java:748)

这是FetchPlayerInfo.run()方法:

@Override
public void run()
{
    String select = "SELECT `Rank`,`Playtime` FROM `Players` WHERE PlayerUUID=?;";

    // This is line 29. How can this possibly be causing a leak?
    try(Connection connection = Database.getHikari().getConnection())
    {
        // Get the data by querying the Players table
        try(PreparedStatement serverSQL = connection.prepareStatement(select))
        {
            serverSQL.setString(1, player);

            // Execute statement
            try(ResultSet serverRS = serverSQL.executeQuery())
            {
                // If a row exists
                if(serverRS.next())
                {
                    String rank = serverRS.getString("Rank");

                    Jedis jPublisher = Redis.getJedis().getResource();
                    jPublisher.publish("playerconnections", player + "~" + serverRS.getInt("Playtime") + "~" + rank);
                }
                else
                {
                    Jedis jPublisher = Redis.getJedis().getResource();
                    jPublisher.publish("playerconnections", player + "~" + 0 + "~DEFAULT");
                }
            }
        }
    }
    catch(SQLException e)
    {
        //Print out any exception while trying to prepare statement
        e.printStackTrace();
    }
}

这是我设置数据库类的方式:

/**
 * This class is used to connect to the database
 */
public class Database
{
    private static HikariDataSource hikari;

    /**
     * Connects to the database
     */
    public static void connectToDatabase(String address,
                                         String db,
                                         String user,
                                         String password,
                                         int port)
    {
        // Setup main Hikari instance
        hikari = new HikariDataSource();
        hikari.setMaximumPoolSize(20);
        hikari.setLeakDetectionThreshold(60 * 1000);
        hikari.setDataSourceClassName("org.mariadb.jdbc.MariaDbDataSource");
        hikari.addDataSourceProperty("serverName", address);
        hikari.addDataSourceProperty("port", port);
        hikari.addDataSourceProperty("databaseName", db);
        hikari.addDataSourceProperty("user", user);
        hikari.addDataSourceProperty("password", password);
    }

    /**
     * Returns an instance of Hikari.
     * This instance is connected to the database that contains all data.
     * The stats table is only used in this database every other day
     *
     * @return The main HikariDataSource
     */
    public static HikariDataSource getHikari()
    {
        return hikari;
    }

这就是我调用FetchPlayerInfo类的方式:

new Thread(new FetchPlayerInfo(player.getUniqueId().toString())).start();

编辑:

使用Database类中的同步getConnection()方法后,问题仍然存在。

2 个答案:

答案 0 :(得分:0)

什么版本的HikariCP?泄漏实际上可能不是泄漏。当连接离开池的时间超过阈值时,将报告泄漏,但实际上可能稍后再返回。较新版本的HikariCP将记录“未泄漏”的连接。

编辑:我几乎可以确定100%可以确定这是HikariCP中没有比赛条件。这种情况远非简单,HikariCP被太多用户(百万)使用,以至于从未出现过这样的基本缺陷。

查看上面的代码和生成的日志,唯一有意义的是外部try-catch内部的调用之一正在挂起(阻塞)。我建议在发生这种情况时进行堆栈转储,以查找FetchPlayerInfo.run()内部是否有线程阻塞。

答案 1 :(得分:0)

Jedis还是JedisPool的resource,您应该关闭:

 /// Jedis implements Closeable. Hence, the jedis instance will be auto-closed after the last statement.
 try (Jedis jedis = pool.getResource()) {