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();
편집:
데이터베이스 클래스에서 동기화된 getConnection() 메서드를 사용해도 문제가 계속 발생합니다.
Jedis는 JedisPool의 리소스이기도 합니다.
/// Jedis implements Closeable. Hence, the jedis instance will be auto-closed after the last statement. try (Jedis jedis = pool.getResource()) {
히카리CP의 어떤 버전입니까?리크가 실제로는 리크가 아닐 가능성이 있습니다.누출은 연결이 임계값을 초과하여 풀을 벗어나면 보고되며, 실제로는 나중에 반환될 수도 있습니다.HikariCP의 최신 버전은 "누출되지 않은" Connections를 기록합니다.
편집: 히카리 CP에 인종 조건이 없다는 것을 100% 가까이 확신합니다.이 시나리오는 너무 간단하지 않으며, HikariCP는 이전에 나타나지 않았던 근본적인 결함을 위해 너무 많은 사용자(수백만 명)에 의해 사용됩니다.
위의 코드와 생성된 로그를 보면 유일하게 일리가 있는 것은 바깥쪽 트라이캐치 내부의 콜 중 하나가 걸려 있다는 것(차단)입니다.상태가 발생하면 스택 덤프를 받아 내부에 스레드가 차단되어 있는지 확인하는 것을 제안합니다.FetchPlayerInfo.run()
.
언급URL : https://stackoverflow.com/questions/51795752/hikaricp-try-with-resources-connection-leaking
'IT' 카테고리의 다른 글
함수 서명에서 제한의 의미는 무엇입니까? (0) | 2023.10.05 |
---|---|
MySQL 데이터베이스의 모든 테이블의 AUTO_INCREMINT 값 업데이트 (0) | 2023.10.05 |
LINQ SelectMany 메서드와 동등한 PowerShell (0) | 2023.10.05 |
C#에서 기본 네임스페이스와 함께 Xpath 사용 (0) | 2023.10.05 |
MySQL 성능: 가입 대 WHERE (0) | 2023.10.05 |