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

Posted

技术标签:

【中文标题】运行测试时Spring Boot“PSQLException:FATAL:抱歉,客户端已经太多”【英文标题】:Spring Boot "PSQLException: FATAL: sorry, too many clients already" when running tests 【发布时间】:2018-04-18 20:46:45 【问题描述】:

我有一个向前端提供 REST API 的 Spring Boot 应用程序。我正在使用 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.max-active = 20 :我认为这是一个错字。 @davidxxx 不,为什么?你的意思是max-active vs maxActive?两者都应该可以正常工作。 不在这一点上。我这么说是因为您指的是 PostgreSQL 中的最大连接数为 200。如果连接数超过20,则会出现错误。不 ?实际上,您不知道当前打开了多少个连接,因为您有错误。这些信息会很有用。 @davidxxx 还指出你的 max-idle 大于你的 max-active,这并没有什么意义,所以看起来 max-active 的值不正确。 200 是我的postgresql.conf 中的max_connections 配置。在我的application.properties 中,我尝试了 max-active 和 max-idle 的各种组合(我也尝试了 max-active = max_connections 而没有指定 max-idle),但我总是遇到 PSQLException。当我收到异常时,我从pg_stat_activity 得到 90 -100 个结果。 【参考方案1】:

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

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

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

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

【讨论】:

【参考方案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 属性指定为小于最大池大小的值,我们告诉 HikariCP 只有在空闲连接数低于该阈值时才添加额外的连接。这可以防止连接池饱和,从而避免遇到太多客户端的情况。

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

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

【讨论】:

我设置为 1 spring.datasource.hikari.minimum-idle=1 这对我有帮助,谢谢【参考方案3】:

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

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

spring.datasource.maximumPoolSize=2

【讨论】:

没有这样的配置属性。至少在 Spring Boot 2 中没有。【参考方案4】:

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

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

【讨论】:

以上是关于运行测试时Spring Boot“PSQLException:FATAL:抱歉,客户端已经太多”的主要内容,如果未能解决你的问题,请参考以下文章

从 cmd 运行时的 Spring Boot 负载测试数据库

使用 DB 运行 Spring Boot 测试时,Jenkins 代理作业被终止

Spring Boot JPA 元模型不能为空!尝试运行 JUnit / 集成测试时

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

运行 Spring Boot MockMvc 测试时“找不到返回值的转换器”

使用属性 server.port=0 运行 spock 测试时如何找到 Spring Boot 容器的端口