JDK 11环境下WebClient调用抛出TimeoutException问题求助
JDK 11环境下WebClient调用TimeoutException问题排查与解决
在JDK 11(zulu-jdk11.0.14)环境中使用WebClient调用接口时,出现如下TimeoutException:
Caused by: java.util.concurrent.TimeoutException: Did not observe any item or terminal signal within 60000ms in 'source(MonoDefer)' (and no fallback has been configured) at reactor.core.publisher.FluxTimeout$TimeoutMainSubscriber.handleTimeout(FluxTimeout.java:295) ~[reactor-core-3.4.24.jar!/:3.4.24]
但在JDK 8(zulu8.61.0.18-sa-jdk8.0.331)环境下运行同一测试用例则完全正常,无异常出现。
应用基于Spring Boot 2.7.5构建,依赖spring-boot-starter-webflux,其中reactor-netty-http版本为1.0.24:
<dependency> <groupId>io.projectreactor.netty</groupId> <artifactId>reactor-netty-http</artifactId> <version>1.0.24</version> </dependency>
观察到的现象
- 现象1:闲置连接异常关闭后,重新调用正常
WebClient调用后闲置约30秒,连接会伴随SslCloseCompletionEvent(java.nio.channels.ClosedChannelException)关闭并注销:
2022-11-14 11:17:47.773 DEBUG 7600 --- [ctor-http-nio-3] reactor.netty.http.client.HttpClient : [3d257d24, L:/xx.xx.xx.xx:64172 - R:nnctj2prxc4t.apps.internal.xxxx.net/xx.xx.xx.xx:443] READ COMPLETE 2022-11-14 11:18:17.264 DEBUG 7600 --- [ctor-http-nio-3] reactor.netty.http.client.HttpClient : [3d257d24, L:/xx.xx.xx.xx:64172 - R:nnctj2prxc4t.apps.internal.xxxx.net/xx.xx.xx.xx:443] READ COMPLETE 2022-11-14 11:18:17.265 DEBUG 7600 --- [ctor-http-nio-3] reactor.netty.http.client.HttpClient : [3d257d24, L:/xx.xx.xx.xx:64172 ! R:nnctj2prxc4t.apps.internal.xxxx.net/xx.xx.xx.xx:443] USER_EVENT: SslCloseCompletionEvent(java.nio.channels.ClosedChannelException) 2022-11-14 11:18:17.265 DEBUG 7600 --- [ctor-http-nio-3] reactor.netty.http.client.HttpClient : [3d257d24, L:/xx.xx.xx.xx:64172 ! R:nnctj2prxc4t.apps.internal.xxxx.net/xx.xx.xx.xx:443] INACTIVE 2022-11-14 11:18:17.265 DEBUG 7600 --- [ctor-http-nio-3] reactor.netty.http.client.HttpClient : [3d257d24, L:/xx.xx.xx.xx:64172 ! R:nnctj2prxc4t.apps.internal.xxxx.net/xx.xx.xx.xx:443] UNREGISTERED
此时再次发送请求,会注册新连接并调用成功:
2022-11-14 11:18:59.542 DEBUG 7600 --- [ctor-http-nio-4] reactor.netty.http.client.HttpClient : [476de49d] REGISTERED 2022-11-14 11:18:59.630 DEBUG 7600 --- [ctor-http-nio-4] reactor.netty.http.client.HttpClient : [476de49d] CONNECT: nnctj2prxc4t.apps.internal.xxxxx.net/xx.xx.xx.xx:443 2022-11-14 11:18:59.743 DEBUG 7600 --- [ctor-http-nio-4] reactor.netty.http.client.HttpClient : [476de49d, L:/xx.xx.xx.xx:64197 - R:nnctj2prxc4t.apps.internal.xxxxx.net/xx.xx.xx.xx:443] ACTIVE 2022-11-14 11:18:59.849 DEBUG 7600 --- [ctor-http-nio-4] reactor.netty.http.client.HttpClient : [476de49d, L:/xx.xx.xx.xx:64197 - R:nnctj2prxc4t.apps.internal.xxxxx.net/xx.xx.xx.xx:443] READ COMPLETE 2022-11-14 11:18:59.858 DEBUG 7600 --- [ctor-http-nio-4] reactor.netty.http.client.HttpClient : [476de49d, L:/xx.xx.xx.xx:64197 - R:nnctj2prxc4t.apps.internal.xxxxx.net/xx.xx.xx.xx:443] USER_EVENT: SslHandshakeCompletionEvent(SUCCESS) 2022-11-14 11:18:59.860 DEBUG 7600 --- [ctor-http-nio-4] reactor.netty.http.client.HttpClient : [476de49d-1, L:/xx.xx.xx.xx:64197 - R:nnctj2prxc4t.apps.internal.xxxxx.net/xx.xx.xx.xx:443] WRITE: 2023B
- 现象2:连接正常关闭后,重新调用触发超时
若连接伴随SslCloseCompletionEvent(SUCCESS)正常关闭并注销:
2022-11-14 09:10:41.295 DEBUG 21332 --- [ctor-http-nio-4] reactor.netty.http.client.HttpClient : [9a6b8e52, L:/xx.xx.xx.xx:56897 - R:nnctj2prxc4t.apps.internal.xxxxx.net/xx.xx.xx.xx:443] CLOSE 2022-11-14 09:10:41.303 DEBUG 21332 --- [ctor-http-nio-4] reactor.netty.http.client.HttpClient : [9a6b8e52, L:/xx.xx.xx.xx:56897 ! R:nnctj2prxc4t.apps.internal.xxxxx.net/xx.xx.xx.xx:443] USER_EVENT: SslCloseCompletionEvent(SUCCESS) 2022-11-14 09:10:41.303 DEBUG 21332 --- [ctor-http-nio-4] reactor.netty.http.client.HttpClient : [9a6b8e52, L:/xx.xx.xx.xx:56897 ! R:nnctj2prxc4t.apps.internal.xxxxx.net/xx.xx.xx.xx:443] READ COMPLETE 2022-11-14 09:10:41.303 DEBUG 21332 --- [ctor-http-nio-4] reactor.netty.http.client.HttpClient : [9a6b8e52, L:/xx.xx.xx.xx:56897 ! R:nnctj2prxc4t.apps.internal.xxxxx.net/xx.xx.xx.xx:443] INACTIVE 2022-11-14 09:10:41.303 DEBUG 21332 --- [ctor-http-nio-4] reactor.netty.http.client.HttpClient : [9a6b8e52, L:/xx.xx.xx.xx:56897 ! R:nnctj2prxc4t.apps.internal.xxxxx.net/xx.xx.xx.xx:443] UNREGISTERED
此时再次发送请求,虽注册新连接但仍触发TimeoutException:
2022-11-14 09:11:32.362 DEBUG 21332 --- [ctor-http-nio-5] reactor.netty.http.client.HttpClient : [ad2bc21d] REGISTERED 2022-11-14 09:11:32.424 DEBUG 21332 --- [ctor-http-nio-5] reactor.netty.http.client.HttpClient : [ad2bc21d] CONNECT: nnctj2prxc4t.apps.internal.xxxxx.net/xx.xx.xx.xx:443 2022-11-14 09:11:32.528 DEBUG 21332 --- [ctor-http-nio-5] reactor.netty.http.client.HttpClient : [ad2bc21d, L:/xx.xx.xx.xx:56922 - R:nnctj2prxc4t.apps.internal.xxxxx.net/xx.xx.xx.xx:443] ACTIVE 2022-11-14 09:11:32.970 DEBUG 21332 --- [ctor-http-nio-5] reactor.netty.http.client.HttpClient : [ad2bc21d, L:/xx.xx.xx.xx:56922 - R:nnctj2prxc4t.apps.internal.xxxxxx.net/xx.xx.xx.xx:443] READ COMPLETE 2022-11-14 09:11:33.063 DEBUG 21332 --- [ctor-http-nio-5] reactor.netty.http.client.HttpClient : [ad2bc21d, L:/xx.xx.xx.xx:56922 - R:nnctj2prxc4t.apps.internal.xxxxxx.net/xx.xx.xx.xx:443] READ COMPLETE 2022-11-14 09:11:33.063 DEBUG 21332 --- [ctor-http-nio-5] reactor.netty.http.client.HttpClient : [ad2bc21d, L:/xx.xx.xx.xx:56922 - R:nnctj2prxc4t.apps.internal.xxxxx.net/xx.xx.xx.xx:443] READ COMPLETE 2022-11-14 09:11:33.165 DEBUG 21332 --- [ctor-http-nio-5] reactor.netty.http.client.HttpClient : [ad2bc21d, L:/xx.xx.xx.xx:56922 - R:nnctj2prxc4t.apps.internal.xxxxx.net/xx.xx.xx.xx:443] USER_EVENT: SslHandshakeCompletionEvent(SUCCESS) ... Caused by: java.util.concurrent.TimeoutException: Did not observe any item or terminal signal within 60000ms in 'source(MonoDefer)' (and no fallback has been configured) at reactor.core.publisher.FluxTimeout$TimeoutMainSubscriber.handleTimeout(FluxTimeout.java:295) ~[reactor-core-3.4.24.jar!/:3.4.24]
解决建议
1. 升级Reactor Netty版本
Reactor Netty 1.0.24存在部分JDK 11兼容性问题,建议升级至1.0.26或更高版本(Spring Boot 2.7.x兼容范围内),新版本修复了JDK 11下的连接管理和SSL相关bug。
修改依赖配置:
<dependency> <groupId>io.projectreactor.netty</groupId> <artifactId>reactor-netty-http</artifactId> <version>1.0.26</version> </dependency>
2. 调整WebClient连接池配置
显式配置连接池的最大空闲时间和生命周期,避免复用已失效的连接:
import io.netty.channel.ChannelOption; import io.netty.handler.timeout.ReadTimeoutHandler; import io.netty.handler.timeout.WriteTimeoutHandler; import reactor.netty.http.client.HttpClient; import reactor.netty.resources.PoolResources; import org.springframework.web.reactive.function.client.WebClient; import org.springframework.http.client.reactive.ReactorClientHttpConnector; import java.time.Duration; WebClient webClient = WebClient.builder() .clientConnector(new ReactorClientHttpConnector( HttpClient.create() .option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 5000) .doOnConnected(conn -> conn .addHandlerLast(new ReadTimeoutHandler(10)) .addHandlerLast(new WriteTimeoutHandler(10))) .poolResources(PoolResources.fixed("webclient-pool", 10) .maxIdleTime(Duration.ofSeconds(20)) .maxLifeTime(Duration.ofSeconds(60))) )) .build();
3. 添加请求重试机制
针对连接超时场景,添加重试策略,确保请求在连接失效时重新发起:
import reactor.util.retry.Retry; import java.util.concurrent.TimeoutException; webClient.get() .uri("/api/xxx") .retrieve() .bodyToMono(String.class) .retryWhen(Retry.fixedDelay(3, Duration.ofSeconds(1)) .filter(throwable -> throwable instanceof TimeoutException)) .block();
4. 调整JDK 11 SSL参数
JDK 11对SSL默认配置做了调整,可显式指定SSL provider或禁用某些特性:
import io.netty.handler.ssl.SslContextBuilder; import io.netty.handler.ssl.SslProvider; import reactor.netty.http.client.HttpClient; HttpClient httpClient = HttpClient.create() .secure(sslContextSpec -> sslContextSpec.sslContext(SslContextBuilder.forClient() .sslProvider(SslProvider.JDK) .build()));
内容的提问来源于stack exchange,提问作者user3787048
相关产品推荐
相关产品推荐

