Spring 在 运行 测试时启动 "PSQLException: FATAL: sorry, too many clients already"

Spring Boot "PSQLException: FATAL: sorry, too many clients already" when running tests

我有一个 Spring 引导应用程序,它向前端提供 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这边。

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

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

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

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

更长的版本:Spring Boot 2 默认使用 HikariCP 作为连接池,连接池大小的默认值为 10(截至 2019 年 1 月)。虽然 运行 很多 IT 会多次创建 Spring 上下文,这意味着每个上下文从数据库获取 10 个连接。据我观察,测试分配连接的速度比释放连接的速度快。因此,在某个时候达到了数据库服务器允许的 max_connections 限制(默认情况下通常为 100),这会导致 "too many clients" 错误。

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

我尝试了几种解决方案,包括 Egemen 提出的解决方案,但都没有用。

对我来说,解决方案是在 application-test.properties:

中使用此配置限制连接池大小
spring.datasource.maximumPoolSize=2

您应该更改 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 属性 指定为小于 max-pool 大小的值,我们告诉 HikariCP 仅当空闲连接数低于该阈值时才添加额外的连接。这可以防止连接池饱和,从而避免遇到 太多客户端 的情况。

但是,HikariCP 确实建议 不要 设置这个 minimum-idle 值,以最大限度地提高性能和对峰值的响应能力需要。我在尝试 运行 测试时遇到了问题,因此我更改了 属性 仅用于测试环境。

我发现 Hikari's Github Page 很有帮助。他们在那里列出了所有这些参数并附有简要说明。一定要看看!

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

IMO 最好的办法是确保所有打开的连接也在您的代码中关闭。