Reactor Netty使用连接池时获取连接超时/队列满该如何解决?
问题根因
你猜测的连接未正确归还就是核心原因,具体问题出在两处:
- 从连接池拿到Connection后,你只触发了发送逻辑的订阅,没有告知连接池该连接什么时候可以被回收,连接池会默认连接一直处于占用状态,20个最大连接全部耗尽后,后续的获取请求只能进入等待队列,最终触发超时或队列满的异常。
- 代码里用了嵌套
subscribe的错误写法,内部发送逻辑的执行状态无法通知到外部的连接获取流,自然也无法触发自动回收逻辑。
修复方案
方式一:主动标记连接可回收
在发送逻辑执行完成(无论成功失败)后,通过doFinally触发连接的回收动作,同时去掉嵌套的subscribe,用响应式操作符串联逻辑:
public void send(String ip, int port, String logText) { TcpClient tcpClient = TcpClient.create(provider) .host(ip) .port(port); tcpClient.connect() // 串联发送逻辑,不要嵌套subscribe .flatMap(connection -> connection.outbound() .sendString(Mono.just(logText)) .then() // 逻辑执行结束后主动归还连接到池 .doFinally(signal -> connection.dispose()) ) // 可选添加异常处理,避免未捕获异常影响业务 .subscribe( success -> System.out.println("数据发送完成"), error -> System.err.println("发送失败:" + error.getMessage()) ); }
这里调用connection.dispose()不会直接销毁连接,而是将连接归还到连接池等待复用,只有连接本身已经失效的情况下才会被销毁重建。
方式二:开启自动闲置连接驱逐
如果担心代码里漏写释放逻辑,可以在构建ConnectionProvider时添加后台驱逐配置,自动回收超过闲置时间的连接:
@PostConstruct public void init() { provider = ConnectionProvider.builder("fixed") .maxConnections(20) .pendingAcquireMaxCount(200) .pendingAcquireTimeout(Duration.ofSeconds(20)) .maxIdleTime(Duration.ofSeconds(10)) .maxLifeTime(Duration.ofSeconds(20)) // 每5秒扫描一次,驱逐符合闲置/生命周期要求的连接 .evictInBackground(Duration.ofSeconds(5)) .build(); }
额外优化建议
- 相同IP和端口的
TcpClient可以复用,不需要每次调用send方法都新建实例,减少不必要的初始化开销。 - 如果是高频向同一目标发送数据的场景,建议复用获取到的连接,不要每次发送都重新申请连接,能大幅提升传输效率。
内容的提问来源于stack exchange,提问作者Leo
相关产品推荐
相关产品推荐

