HikariPool-1 - 连接不可用,请求在非常轻微的负载服务器上超时了30000ms

52

我有一个小的Java应用程序,用于测试目的。最近我已经改用Hikari了。我注意到的是我一直得到这个错误。

java.sql.SQLTransientConnectionException: HikariPool-1 - Connection is not available, request timed out after 30000ms.
java.sql.SQLTransientConnectionException: HikariPool-1 - Connection is not available, request timed out after 30000ms.
at com.zaxxer.hikari.pool.HikariPool.createTimeoutException(HikariPool.java:602)
at com.zaxxer.hikari.pool.HikariPool.getConnection(HikariPool.java:195)
at com.zaxxer.hikari.pool.HikariPool.getConnection(HikariPool.java:145)
at com.zaxxer.hikari.HikariDataSource.getConnection(HikariDataSource.java:85)

以下是我最初的 Hikari 设置。

 HikariConfig config = new HikariConfig();
            config.setJdbcUrl("jdbc:mysql://localhost:3306/****"); 
            config.setUsername("***"); 
            config.setPassword("*****");      
            config.setMaximumPoolSize(20);  

我的两个设备几乎没有使用过它,并且我确保在最后关闭了它。所以我不知道为什么它还是一直出现错误?可能是什么问题或者是否有一些设置需要更改?

我的 Hikari 版本是 HikariCP-2.6.1.jar。


1
请在您的问题中添加Hikari版本和其他Hikari设置。 - user7294900
1
我的Hikari版本是HikariCP-2.6.1.jar。除了上述问题中提到的设置外,我没有其他设置。谢谢。 - user8012596
14个回答

32

由于网络延迟或某些查询执行时间过长(超过30000毫秒),您的数据库未能在默认的connectionTimeout属性(30000毫秒)内获得连接。

请尝试增加connectionTimeout属性值。

YML配置示例:

spring:
  datasource:
    hikari:
      minimumIdle: 2
      maximumPoolSize: 10
      idleTimeout: 120000
      connectionTimeout: 300000
      leakDetectionThreshold: 300000

Java配置示例:

HikariConfig config = new HikariConfig();
        config.setMaximumPoolSize(20);
        config.setConnectionTimeout(300000);
        config.setConnectionTimeout(120000);
        config.setLeakDetectionThreshold(300000);

假设我们所有的端点运行时间都不超过2秒,那么在尝试获取连接时超时的原因可能是什么?我们的应用程序在单个实例下运行良好,但一旦水平扩展,我们就会在所有新创建的应用程序中遇到这些错误。 - payne
1
@payne,我有点晚了回复这个评论,但如果你在水平扩展时遇到这个问题,我猜测你可能已经耗尽了数据库服务器的连接限制。 - nelsonda
41
对于阅读最受欢迎答案的人,需要注意一个重要的警告:增加超时时间可能会解决症状,但几乎肯定无法解决根本问题。 - IcedDante
1
这里的问题似乎更可能通过增加DB服务器/池中允许的连接数来解决,而不是增加超时时间。如果您必须等待30秒才能从池中获取连接,那真的是不可接受的。 - Josh M.
是连接到数据库,还是等待池中的一个可用连接? - undefined

10

我正在使用Spring Boot,之前遇到了相同的问题,我的解决方法是通过这样获取连接:DataSourceUtils.getConnection(dataSource)。所以我改变了从dataSource.getConnection()DataSourceUtils.getConnection(dataSource)


2
你是如何初始化传递给DataSourceUtils.getConnection(dataSource)的"dataSource"参数的? - MedMahmoud
1
@Autowired private DataSource dataSource; @Autowired 私有数据源。 - Andres Rincon
1
这个SO问题有更多关于为什么的信息:https://dev59.com/Hmkw5IYBdhLWcg3wyNoW - mowwwalker
我曾经遇到过完全相同的问题,我使用了上面的解决方案,它完美地解决了我的问题!我很好奇当获取连接时DatSourceUtils做了什么不同的事情。 - Ev.Rei.

8

在我的情况下,我在使用JPA以及在SpringBoot项目中使用EntityManagerFactory实现持久化和查询时也遇到了同样的错误。

原因是我没有在任何CRUD操作完成后关闭EntityManager,导致资源耗尽。

希望这可以帮到你!

EntityManager em = emf.createEntityManager();
       Customer c  = em.find(Customer.class , id);
        em.close();

3
如果实体管理器是自动装配的,我们需要关闭它吗? - TheRealChx101
1
不,容器应该在事务边界内进行管理。 - Nanotron

7

在我的情况下,代码没有关闭连接。

使用“try-with-resources”解决了这个问题:

try (
    Connection connection = dataSource.getConnection();
    Statement statement = …
) {
…
}


1
我不明白你的意思?你使用的是哪个Java版本? - user8012596
1
自Java 7以来,Try with resources已经存在。 - Vlad L
我用实体管理器做了同样的事情,同样的事情只是不同的颜色。 - alegria

3

在我的情况下:

o.h.engine.jdbc.spi.SqlExceptionHelper: HikariPool-1 - Connection is not available, request timed out after 30019ms.
i.s.commons.web.error.ExceptionLogger: Internal Server Error
org.springframework.transaction.CannotCreateTransactionException: Could not open JPA EntityManager for transaction; nested exception is org.hibernate.exception.JDBCConnectionException: Unable to acquire JDBC Connection

这是由应用程序属性中的spring.hikari.maximumPoolSize设置过低引起的,将其从5增加到20解决了该问题。 日志消息有点误导。


2

如果客户端应用程序请求了大量的打开连接,并且数据库服务器设置了池连接数的最大限制,则也可能发生这种情况。因此,客户端应用程序无法从数据库服务器获取更多连接。检查数据库服务器的连接池,以查看在错误发生期间是否超过了最大值。


有没有办法检查特定时间段内数据库的开放连接数量? - Akshansh Jain
是的,每个数据库如MySQL、PostgreSQL都有列出打开连接数量的命令,您可以定期运行。请进行谷歌搜索。 - ebeb

2

请求超时不是仅通过增加超时时间就能解决的问题。也许你需要评估服务中的所有查询,并在必要时实施索引。


2
我已经解决了我的问题,使用了以下方法:
增加 minIdle 和 maxPool。
spring.datasource.hikari.minimumIdle=20
spring.datasource.hikari.maximumPoolSize=30
spring.datasource.hikari.connectionTimeout=50000

为了调试问题/检查值是否正确,请启用Hikari的日志记录。
logging.level.com.zaxxer.hikari.HikariConfig=DEBUG 
logging.level.com.zaxxer.hikari=TRACE

日志将如下所示:

DEBUG 2023-01-06T16:12:31.932018849Z  HikariPool-1 - Before cleanup stats (total=17, active=0, idle=17, waiting=0)
DEBUG 2023-01-06T16:12:31.932665522Z  HikariPool-1 - After cleanup stats (total=17, active=0, idle=17, waiting=0)
DEBUG 2023-01-06T16:12:31.932733949Z  HikariPool-1 - Fill pool skipped, pool is at sufficient level.
DEBUG 2023-01-06T16:12:32.495269726Z  HikariPool-1 - After adding stats (total=17, active=0, idle=17, waiting=0)
DEBUG 2023-01-06T16:12:38.309953158Z  HikariPool-1 - Fill pool skipped, pool is at sufficient level.
DEBUG 2023-01-06T16:12:39.200246897Z  HikariPool-1 - Fill pool skipped, pool is at sufficient level.
DEBUG 2023-01-06T16:12:44.812065268Z  HikariPool-1 - Before cleanup stats (total=18, active=0, idle=18, waiting=0)
DEBUG 2023-01-06T16:12:44.812822113Z  HikariPool-1 - After cleanup stats (total=18, active=0, idle=18, waiting=0)

祝你好运! :)
警告: 请小心,一个很大的maximumPoolSize可能是一种代码异味,并且可能隐藏了性能问题,例如:长时间事务。此外,数据库供应商建议使用较小的maximumPoolSize,例如:maximumPoolSize=10。maximumPoolSize的值越大,将会影响数据库的性能。

1

花了很长时间才弄明白...在我的情况下,我使用了类似于@Andres Rincon的解决方案:

try (Connection connection = DataSourceUtils.getConnection(jdbcTemplate.getDataSource())) {
    // some code here
}

1

通常情况下,未关闭的连接会导致此问题。应用服务器连接数据库有一定限制,如果超过限制,则会导致环境崩溃。

连接必须建立在单例模式上,但如果您确实需要打开数据源或连接外部数据源(如报告),则必须在finally块中关闭连接。

connection.getConnection().rollback();
connection.getConnection().close();

如果您正在使用非单例的PersistenceJpa,那么您也必须关闭它。

persistenceJPAConfig.dataSource().getConnection().rollback();
persistenceJPAConfig.dataSource().getConnection().close();

如果您正在使用创建线程进行压力测试工具来测试方法,则可能会在执行时间较长的查询上收到此错误。这将引导优化查询或服务实例大小的方式。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接