Hibernate Reactive在AWS RDS环境中随机抛出HR000065: No Vert.x context active异常问题排查
问题拆解
先明确你碰到的核心问题:
- 随机出现
HR000065: No Vert.x context active异常,栈指向PrincipalController#getUserAuthentication()接口 - 异常出现几次后,所有数据库请求超时,连接池被占满无法释放
- 本地环境(包括SSH连接生产RDS)完全正常,仅AWS RDS生产环境触发
你提供的异常栈参考:
HR000065: No Vert.x context active java.lang.IllegalStateException: HR000065: No Vert.x context active 2021-11-09T17:12:18.143+02:00 at org.hibernate.reactive.context.impl.VertxContext.put(VertxContext.java:41) ~[hibernate-reactive-core-1.0.1.Final.jar!/:1.0.1.Final] 2021-11-09T17:12:18.143+02:00 Suppressed: reactor.core.publisher.FluxOnAssembly$OnAssemblyException: 2021-11-09T17:12:18.143+02:00 Error has been observed at the following site(s): 2021-11-09T17:12:18.143+02:00 |_ checkpoint ⇢ Handler com.nflp.processingapplication.main.modules.authentication.controller.PrincipalController#getUserAuthentication() [DispatcherHandler] 2021-11-09T17:12:18.143+02:00 |_ checkpoint ⇢ com.nflp.processingapplication.main.modules.api.shared.filter.ApiExceptionFilter
根因分析
这个HR000065异常本质是Hibernate Reactive的数据库操作脱离了Vert.x上下文——Hibernate Reactive依赖Vertx Context绑定会话、事务和线程上下文,一旦代码跑到非Vert.x管理的线程里执行数据库操作,就会抛出这个错误。
为什么仅生产环境触发?核心是生产环境的网络延迟和线程调度特性放大了本地不易复现的上下文泄漏:
- 本地网络延迟低,请求处理快,线程上下文切换少,异步操作基本都能在原Vertx Context内完成
- AWS RDS与应用的网络延迟更高,请求处理周期变长,线程池调度更复杂,某些异步操作可能意外跳出了原Vertx Context(比如线程池饱和导致任务被分配到非Vertx线程)
而后续的连接超时,是因为异常导致会话/事务未被正确关闭,连接池连接被耗尽,新请求拿不到连接就超时了。
针对性解决方案
1. 优先升级Hibernate Reactive版本
你当前使用的1.0.1.Final是早期稳定版,存在不少上下文传递的Bug。后续的1.1.x、2.x版本修复了大量类似的随机上下文丢失问题,升级到最新稳定版(比如2.2.x)大概率能直接解决这个问题。
2. 规范异步操作的上下文传递
从栈信息能看出是Spring WebFlux环境(DispatcherHandler),要确保所有数据库操作都在Reactive流的上下文内:
- 禁止在
subscribe()、block()之后调用Hibernate Reactive方法:subscribe()会脱离当前上下文,切换到线程池的非Vertx线程,此时调用withTransaction/withSession就会丢失上下文 - 控制器方法必须返回
Mono/Flux,不要手动开启线程处理数据库操作 - 检查自定义过滤器/拦截器(比如你的
ApiExceptionFilter)是否存在阻塞操作或手动线程切换,这类操作会破坏上下文传递
3. 调整AWS RDS对应的连接池配置
生产环境的连接池参数需要适配RDS特性:
- 合理设置连接池
maxSize:不要太小(避免快速耗尽)也不要太大(给RDS造成压力),建议根据RDS实例规格调整(比如t3.medium可以设为10-15) - 配置连接超时和空闲回收:设置
connectionTimeout(比如30s)和idleTimeout(比如60s),让连接池能及时回收异常情况下的闲置连接 - 开启Hibernate Reactive的连接池监控:通过日志或指标查看连接池的占用情况,确认是不是异常导致连接无法释放
4. 排查上下文丢失的具体场景
可以在关键节点添加日志,定位上下文丢失的时机:
// 在getUserAuthentication()方法开头添加 Optional<VertxContext> currentCtx = VertxContext.current(); if (!currentCtx.isPresent()) { log.warn("⚠️ No Vert.x context found in getUserAuthentication! Thread: {}", Thread.currentThread().getName()); }
这样当异常出现时,你能看到当前线程是否属于Vertx线程池,进而定位是哪一步操作导致了上下文丢失。
5. 检查AWS RDS的网络配置
虽然本地SSH连RDS没问题,但生产环境的RDS可能存在网络抖动或连接中断的情况,某些异常连接未被及时清理,也可能间接触发上下文问题。可以查看RDS的CloudWatch指标,检查连接数、延迟等数据是否有异常波动。
总结
这个问题的核心是随机的Vertx上下文丢失,生产环境的网络和线程调度特性让这个问题显现出来,进而导致连接池耗尽。优先升级Hibernate Reactive版本,再规范异步操作的上下文传递,这两个步骤解决过很多类似的问题。
内容的提问来源于stack exchange,提问作者Dmytro Kostyushko

