R2DBC 池在每次查询前关闭所有连接

R2DBC pool closes all connections before each query

我们使用最新版本的 spring-data-r2dbcr2dbc-poolr2dbc-postgresql 通过连接池连接到 PostgreSQL 数据库。我们注意到一些高响应时间,远高于从数据库本身获取的查询响应时间 (query_store.qs_view)

我们向池中添加了一个 metricsRecorder,出于调试目的,我们仅在调用每个方法时才打印。似乎在每个 SQL 查询之前,我们得到与池中连接数一样多的 recordDestroyLatency 调用和相同数量的 recordAllocationSuccessAndLatency 调用。我们假设这意味着每个连接在每次查询之前都会关闭并重新打开。然后我们与数据库日志进行了比较,结果证明这是真的:could not receive data from client: An existing connection was forcibly closed by the remote host 后跟 connection received: 条消息的数量相同。

为什么会这样?下面是我们用于创建连接工厂的代码。

@Configuration
open class DatabaseConfiguration : AbstractR2dbcConfiguration() {

//some variable initialisations

    @Bean
    override fun connectionFactory(): ConnectionFactory {
        val cf = PostgresqlConnectionFactory(
            PostgresqlConnectionConfiguration.builder()
                .host(hostname)
                .database(dbName)
                .schema(dbSchema)
                .username(dbUsername)
                .password(dbPassword)
                .build()
        )
        val cp = ConnectionPoolConfiguration.builder(cf)
            .initialSize(poolInitialSize)
            .maxSize(poolMaxSize)
            .metricsRecorder(DatabaseMetricsRecorder())
            .build()
        return ConnectionPool(cp)
    }
}

如前所述,DatabaseMetricsRecorder 仅打印每个操作。对于查询本身,我们正在扩展 ReactiveCrudRepository 接口。 ConnectionPoolConfiguration 在这里是最简单的形式,我们尝试添加像 maxIdleTimevalidationQuery 这样的参数(因为我们将在生产中使用)但它似乎没有帮助。

这是 R2DBC 池中的一个已知错误,这里是 issue。作为解决方法,应该明确设置 maxLifeTime,例如我将其设置为以毫秒为单位的最大允许值(否则,如果设置为大于以毫秒为单位的最大允许值的值,R2DBC 将抛出异常):

    val cp = ConnectionPoolConfiguration.builder(cf)
        .initialSize(poolInitialSize)
        .maxSize(poolMaxSize)
        .maxLifeTime(Duration.ofMillis(Long.MAX_VALUE))
        .metricsRecorder(DatabaseMetricsRecorder())
        .build()