You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Quarkus Reactive负载测试时数据库连接未及时释放,抛出‘Session is currently connecting to database’等错误求助

Quarkus Reactive应用k6负载测试时数据库连接无法及时释放,出现Session超时/关闭错误

问题描述

我在对Quarkus Reactive应用进行k6负载测试时遇到了问题,看起来数据库连接无法及时释放。该应用的端点逻辑为:根据接收到的code查询数据库实体,然后存储一条与该实体关联的新事件。核心代码如下:

@GET 
@PermitAll 
@Path("s/") 
@Produces(MediaType.TEXT_PLAIN) 
public Uni<Response> request(@PathParam("code") String code) { 
    return myService.fetchEntityByCode(code) 
        .onItem().invoke(entity-> { 
            //persist the events here 
            persist(SomeEvent.builder().entity(entity).build()); 
        }) 
        .onItem().transform(entity-> { 
            Response.ResponseBuilder builder = new ResponseBuilderImpl(); 
            //do some other things to build the response 
            return builder.build(); 
        }); 
}

private void persist(MyEvent myEvent) { 
    Panache.withTransaction(myEvent::persist) 
        .onFailure().invoke(throwable -> log.error("Persisting failed", throwable)) 
        .subscribe().with(p -> { 
            //just a dummy subscriber to get "fire&forget" behaviour 
        }); 
}

运行k6负载测试后,我收到了以下错误信息,推测这与连接未及时释放导致后续无法创建新数据库连接有关:

2022-01-30 17:04:04,865 DEBUG [org.hib.res.jdb.int.LogicalConnectionManagedImpl] (vert.x-eventloop-thread-6) `hibernate.connection.provider_disables_autocommit` was enabled. This setting should only be enabled when you are certain that the Connections given to Hibernate by the ConnectionProvider have auto-commit disabled. Enabling this setting when the Connections do not have auto-commit disabled will lead to Hibernate executing SQL operations outside of any JDBC/SQL transaction. 
2022-01-30 17:04:05,052 ERROR [com.lau.lin.MyResource] (vert.x-eventloop-thread-11) Persisting failed 
2022-01-30 17:04:05,052 ERROR [io.qua.mut.run.MutinyInfrastructure] (vert.x-eventloop-thread-11) Mutiny had to drop the following exception: io.smallrye.mutiny.CompositeException: Multiple exceptions caught: [Exception 0] io.vertx.core.impl.NoStackTraceThrowable: Timeout [Exception 1] java.lang.IllegalStateException: HR000060: Session is closed 
...(省略部分栈追踪)
Suppressed: java.lang.IllegalStateException: HR000060: Session is closed 
...(省略部分栈追踪)
Caused by: io.vertx.core.impl.NoStackTraceThrowable: Timeout 

以及:
2022-01-30 16:29:53,581 ERROR [com.lau.lin.MyService] (vert.x-eventloop-thread-10) Persisting failed: io.smallrye.mutiny.CompositeException: Multiple exceptions caught: [Exception 0] java.lang.IllegalStateException: HR000061: Session is currently connecting to database [Exception 1] java.lang.IllegalStateException: HR000061: Session is currently connecting to database 
...(省略部分栈追踪)

请问我遗漏了什么配置或代码逻辑?


回答

问题根源

你的核心问题在于异步持久化操作的生命周期脱离了请求上下文:

  • 在persist方法中,你使用subscribe().with()实现"fire&forget",这会让事务操作在后台独立运行,Quarkus的Reactive连接管理器无法追踪这些连接的使用情况,导致连接无法被及时回收。
  • 同时,你在请求链中用onItem().invoke()调用persist,invoke是同步执行的,不会等待异步的持久化操作完成,请求返回后,相关的上下文资源(包括数据库连接)可能被提前回收,进而引发Session关闭、连接超时等错误。
  • 高负载下,大量未被回收的连接会耗尽连接池,导致后续请求无法获取新连接,出现你看到的超时和Session异常。

解决方案

你需要把持久化操作的Uni纳入到请求的响应链中,让Quarkus能够正确管理事务和连接的生命周期。具体修改如下:

1. 修改persist方法,返回Uni<Void>

去掉subscribe().with(),让方法返回事务操作的Uni,这样可以将其纳入请求链:

private Uni<Void> persist(MyEvent myEvent) { 
    return Panache.withTransaction(myEvent::persist) 
        .onFailure().invoke(throwable -> log.error("Persisting failed", throwable)); 
}

2. 修改请求链,使用call替代invoke

call操作符会等待传入的Uni执行完成后再继续链的流程,确保持久化操作在请求响应完成前完成,连接能被正确回收:

@GET 
@PermitAll 
@Path("s/{code}") // 注意:原Path "s/"无法正确匹配@PathParam("code"),这里修正为带参数的路径
@Produces(MediaType.TEXT_PLAIN) 
public Uni<Response> request(@PathParam("code") String code) { 
    return myService.fetchEntityByCode(code) 
        .call(entity -> persist(SomeEvent.builder().entity(entity).build())) // 用call执行异步持久化,等待完成
        .onItem().transform(entity-> { 
            // 用Response.ok()替代手动new ResponseBuilderImpl(),更简洁符合规范
            Response.ResponseBuilder builder = Response.ok(); 
            //do some other things to build the response 
            return builder.build(); 
        }); 
}

3. 优化连接池配置(可选但推荐)

检查你的application.properties,确保Reactive数据库连接池的配置符合负载需求:

# 调整连接池最大大小,根据你的负载情况设置合理值
quarkus.datasource.reactive.max-size=20
# 设置连接空闲超时,回收闲置连接
quarkus.datasource.reactive.idle-timeout=30s
# Hibernate Reactive连接池大小和数据源保持一致
quarkus.hibernate-orm.reactive.connection-pool.max-size=20

为什么这样修改有效

  • 将持久化操作的Uni纳入请求链后,Quarkus可以追踪整个异步流程的生命周期,确保事务完成后及时释放数据库连接。
  • call操作符保证了持久化操作在响应返回前完成,避免了上下文资源被提前回收的问题。
  • 去掉"fire&forget"的订阅方式,消除了连接泄漏的根源,高负载下连接池不会被耗尽。

内容的提问来源于stack exchange,提问作者Marian Klühspies

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.28 10:42:44