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 个空闲连接。所以这会产生两个问题:
- 为什么我的测试失败了,尽管我的本地数据库应该允许比我在
pg_stat_activity
中看到的更多的连接?
- 看来我的
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 最好的办法是确保所有打开的连接也在您的代码中关闭。
我有一个 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 个空闲连接。所以这会产生两个问题:
- 为什么我的测试失败了,尽管我的本地数据库应该允许比我在
pg_stat_activity
中看到的更多的连接? - 看来我的
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 最好的办法是确保所有打开的连接也在您的代码中关闭。