运行测试时出现Spring Boot "PSQLException: FATAL: sorry, too many clients already"错误

31

我有一个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这一侧。

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

  1. 为什么我的测试会失败,尽管我的本地数据库应该允许更多的连接,而不是我在pg_stat_activity中看到的数量?
  2. 似乎我的application.properties中的数据源配置被忽略了。有什么想法吗?

1
spring.datasource.max-active = 20:我认为这是一个打字错误。 - davidxxx
1
@davidxxx 不好意思,你的意思是 max-active 和 maxActive 之间有什么区别吗?两者都应该可以正常工作。 - Egemen
1
不是这个问题。我之所以这么说,是因为你提到了 PostgreSQL 中的最大连接数为 200。如果连接数超过了20,那么就会出现错误,对吧?实际上,你没有告诉我们当前有多少连接已经打开了,这个信息很有用。 - davidxxx
1
@davidxxx 还指出你的 max-idle 大于 max-active,这并不太合理,因此看起来 max-active 的值是不正确的。 - Pytry
1
我的 postgresql.confmax_connections 的配置值是 200。在我的 application.properties 文件中,我尝试了各种 max-active 和 max-idle 的组合(我还尝试了将 max-active 设置为 max_connections 并且不指定 max-idle),但我总是遇到 PSQLException 异常。当我收到异常时,从 pg_stat_activity 中获取的结果在 90 到 100 之间。 - Egemen
显示剩余2条评论
4个回答

54

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


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

更详细的版本:Spring Boot 2默认使用HikariCP进行连接池,其连接池大小的默认值为10(截至2019年1月)。在运行许多ITs时,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属性指定为小于max-pool大小的较小值,我们告诉HikariCP仅在空闲连接数低于该阈值时添加其他连接。这可以防止连接池过度饱和,从而遇到“too many clients”情况。

但是,HikariCP建议不要设置此minimum-idle值,以最大化性能和对峰值需求的响应能力。我在尝试运行测试时遇到了问题,因此我仅为测试环境更改了此属性。

我发现Hikari的Github页面非常有帮助。在那里,他们列出了所有这些参数及简要说明。请看一下!


我将其设置为1 spring.datasource.hikari.minimum-idle=1 - notes-jj

3

我尝试了几个解决方案,包括Egemen提出的方案,但它们都没有起作用。

对我来说,解决方案是使用application-test.properties中的以下配置限制连接池大小:

spring.datasource.maximumPoolSize=2

3
没有这样的配置属性,至少在Spring Boot 2中是没有的。 - Turzo

0

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

我认为最好的做法是确保你的代码中所有打开的连接也都被关闭了。


2
我正在使用JPA.. 有什么线索可以帮助我找到这个泄漏吗? - Aspiring Dev

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