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

Spring Cloud Hoxton版本WebClient阻塞Netty主线程问题咨询

问题原因与解决方案

核心问题根源

  • 你观察到的阻塞现象根本不是第一个应用的Netty主线程被阻塞,问题出在第二个模拟服务的代码完全不符合WebFlux的非阻塞编码规范:
    WebFlux控制器的默认执行线程是Netty的事件循环(Event Loop)线程,你直接在test方法中调用Thread.sleep(15000L),是直接把第二个应用自身的Netty工作线程给阻塞了,导致它在15秒休眠结束前无法处理任何新请求,包括第一个应用通过WebClient发送的后续请求,表现出来就像是第一个应用被阻塞了。
  • 你添加的publishOn调度器位置错误,且该场景完全不需要额外配置调度器:publishOn只会作用于它之后的操作符链,你注释的代码是把publishOn放在bodyToMono之后,就算启用也管不到WebClient的请求发送逻辑,更何况WebClient本身默认就是非阻塞实现,不会占用调用方的事件循环线程。

验证第一个应用未阻塞的方法

你可以在第一个应用中新增一个无需调用外部服务的测试接口:

@GetMapping("/localTest")
open fun localTest(): Mono<String> {
    return Mono.just("local response")
}

在触发15秒休眠的请求后,立即调用这个本地接口,会发现接口秒返回,即可验证第一个应用的Netty主线程完全没有被阻塞。

修复方案

修改第二个模拟服务的代码,不要直接在控制器中使用Thread.sleep这类阻塞API,改用WebFlux原生的非阻塞延时实现:

@GetMapping("/test")
open fun test(): Mono<String> {
    return Mono.delay(Duration.ofSeconds(15))
            .thenReturn("Hello")
}

如果你的实际业务场景中存在不可避免的阻塞操作(比如同步IO、第三方阻塞SDK调用等),需要将阻塞逻辑调度到专门的弹性线程池执行,不要占用事件循环线程:

@GetMapping("/test")
open fun test(): Mono<String> {
    return Mono.fromCallable {
        // 阻塞逻辑放在fromCallable中
        Thread.sleep(15000L)
        "Hello"
    }.subscribeOn(Schedulers.boundedElastic())
}

内容的提问来源于stack exchange,提问作者Don Donovan

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.04 01:54:05