Spring Boot 运行测试时出现“PSQLException: FATAL: 抱歉,已经有太多客户端”

问题描述 投票:0回答:5

我有一个 Spring Boot 应用程序,它为前端提供 REST API。我正在使用 jOOQ 和 Postgresql。目前,我在本地执行所有集成测试时遇到此错误(大约 1000 个测试,在执行 700-800 个测试后开始发生这种情况):

org.postgresql.util.PSQLException: FATAL: sorry, too many clients already

我尝试通过

application.properties
限制最大空闲和活动连接,但似乎这些值在某种程度上被忽略了。我只是在使用以下语句执行测试时监视打开的连接:

SELECT datname, state, query FROM pg_stat_activity;

这就是我的 application.properties 的样子:

spring.datasource.driverClassName = org.postgresql.Driver
spring.datasource.url = jdbc:postgresql://localhost:5432/xxx
spring.datasource.username = xxx
spring.datasource.password = xxx
spring.datasource.initialize = true
spring.datasource.continue-on-error = false
spring.jooq.sql-dialect = POSTGRES
spring.datasource.max-active = 50
spring.datasource.max-idle = 5

这就是我创建数据源的方式:

@ConfigurationProperties(prefix = "spring.datasource")
@Bean
public DataSource dataSource() {
    return DataSourceBuilder
            .create()
            .build();
}

我看到jOOQ使用了正确的数据源,并且jOOQ正确地处理了连接(从数据源获取和释放连接)。所以问题不应该出在jOOQ这边。

我的

max_connections = 200
中有
postgresql.conf
,所以我的Spring配置应该没问题。在运行测试时,我发现
pg_stat_activity
中的空闲连接比我在配置中指定的连接多得多。最终,当测试由于
PSQLException
而开始失败时,我在
pg_stat_activity
中看到大约 90-100 个空闲连接。所以这会产生两个问题:

  1. 为什么我的测试失败,尽管我的本地数据库应该允许比我在
    pg_stat_activity
    中看到的更多的连接?
  2. 看来我的
    application.properties
    中的数据源配置被忽略了。知道为什么吗?
postgresql spring-boot datasource
5个回答
55
投票

由于没有建议的答案,我正在发布我的解决方案。 简短版本:减小测试属性中的连接池大小:

spring.datasource.hikari.maximum-pool-size=2

较长版本:Spring Boot 2 默认使用 HikariCP 进行连接池,连接池大小的默认值为 10(截至 2019 年 1 月)。在运行大量 IT 时,Spring 上下文会被创建多次,这意味着每个上下文从数据库获取 10 个连接。据我观察,测试分配连接的速度比释放连接的速度快。因此,在某个时刻会达到数据库服务器允许的

max_connections
限制(默认情况下通常为 100),从而导致“客户端过多”错误。

通过在测试属性中将连接池大小限制为 2,我能够解决该问题。


17
投票

您应该更改

minimum-idle
属性,而不是
maximum-pool-size

spring.datasource.hikari.minimum-idle=5

maximum-pool-size
的默认值为10,
minimum-idle
默认与max-pool-size相同。将其更改为比 max-pool-size 更小的值对我来说很有效。

我的预感是,应用程序在执行并行运行的测试时会尝试与数据库建立大量连接。然而,这些连接的使用时间非常短,一个连接可以很容易地被多个测试实例重复使用。通过将

minimum-idle
属性指定为小于最大池大小的值,我们告诉 HikariCP 仅当空闲连接数低于该阈值时才添加其他连接。这可以防止连接池饱和,从而避免遇到“客户端过多”的情况。 但是,HikariCP 确实建议

不要设置此minimum-idle值,以便最大限度地提高性能和对峰值需求的响应能力。我在尝试运行测试时遇到了问题,因此我仅为测试环境更改了属性。

我发现 

Hikari 的 Github 页面

非常有帮助。在那里他们列出了所有这些参数并附有简短的解释。一定要看看!


3
投票
Egemen

提出的解决方案,但它们不起作用。 对我来说,解决方案是使用以下配置来限制连接池大小:

application-test.properties

    

我在集成测试 Spring Boot 应用程序并使用 Testcontainers 时遇到了这个问题。我注意到我的连接泄漏导致了这种情况的发生。

0
投票

这些解决方案都不适合我。 应用程序上下文在测试之间进行缓存,以帮助加快测试速度,因此用

spring.datasource.maximumPoolSize=2

0
投票
@SpringBootTest

的类)对我来说很有效。


当使用 @DirtiesContext 标记测试时,Spring 会在执行测试之前或之后销毁并重新创建应用程序上下文,具体取决于指定的选项。这确保每个测试从独立于其他测试的干净应用程序状态开始。

© www.soinside.com 2019 - 2024. All rights reserved.