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
相关产品推荐
相关产品推荐

