当前位置: 首页 > 知识库问答 >
问题:

WebClient第一次请求缓慢的解决方法

史昀
2023-03-14

我在Spring Boot MVC 2.1项目中使用WebClient,发现客户端发出的第一个请求需要6秒。后续请求的速度要快得多(~30ms)。

在Spring的JIRA中有一个封闭的问题,建议使用Jetty作为WebClient Http连接器。我已经尝试了这种方法,改进了数字,第一个请求约为800ms。这次是一个改进,但它仍然远离RestTemplate,它通常采取

Netty 方法(5 秒第一个请求):

会议:

@Bean
public WebClient webClient() {
    return WebClient.create();
}

用法:

private final WebClient webClient;

@GetMapping(value="/wc", produces = APPLICATION_JSON_UTF8_VALUE)
public Mono<String> findWc() throws URISyntaxException {
    URI uri = new URI("http://xxx");
    final Mono<String> response = webClient.get().uri(uri).retrieve().bodyToMono(String.class);
    return response;
}

码头进场(800ms第一次请求):

会议:

@Bean
public JettyResourceFactory resourceFactory() {
    return new JettyResourceFactory();
}

@Bean
public WebClient webClient() {
    ClientHttpConnector connector = new JettyClientHttpConnector(resourceFactory(), null);
    return WebClient.builder().clientConnector(connector).build();
}

用法:与以前相同。

突堤方法还有另一个“问题”。服务器关闭时,它总是会产生以下异常:

27-Dec-2018 11:24:20.463 INFO [jetty-http@74305db9-65] org.apache.catalina.loader.WebappClassLoaderBase.checkStateForResourceLoading Illegal access: this web application instance has been stopped already. Could not load [org.eclipse.jetty.io.ManagedSelector$StopSelector]. The following stack trace is thrown for debugging purposes as well as to attempt to terminate the thread which caused the illegal access.
 java.lang.IllegalStateException: Illegal access: this web application instance has been stopped already. Could not load [org.eclipse.jetty.io.ManagedSelector$StopSelector]. The following stack trace is thrown for debugging purposes as well as to attempt to terminate the thread which caused the illegal access.
    at org.apache.catalina.loader.WebappClassLoaderBase.checkStateForResourceLoading(WebappClassLoaderBase.java:1348)
    at org.apache.catalina.loader.WebappClassLoaderBase.checkStateForClassLoading(WebappClassLoaderBase.java:1336)
    at org.apache.catalina.loader.WebappClassLoaderBase.loadClass(WebappClassLoaderBase.java:1195)
    at org.apache.catalina.loader.WebappClassLoaderBase.loadClass(WebappClassLoaderBase.java:1157)
    at java.lang.Class.getDeclaringClass0(Native Method)
    at java.lang.Class.getDeclaringClass(Class.java:1235)
    at java.lang.Class.getEnclosingClass(Class.java:1277)
    at java.lang.Class.getSimpleBinaryName(Class.java:1443)
    at java.lang.Class.getSimpleName(Class.java:1309)
    at org.eclipse.jetty.io.ManagedSelector$SelectorProducer.toString(ManagedSelector.java:534)
    at java.lang.String.valueOf(String.java:2994)
    at java.lang.StringBuilder.append(StringBuilder.java:131)
    at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.getString(EatWhatYouKill.java:458)
    at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.toStringLocked(EatWhatYouKill.java:447)
    at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.toString(EatWhatYouKill.java:440)
    at org.slf4j.helpers.MessageFormatter.safeObjectAppend(MessageFormatter.java:299)
    at org.slf4j.helpers.MessageFormatter.deeplyAppendParameter(MessageFormatter.java:271)
    at org.slf4j.helpers.MessageFormatter.arrayFormat(MessageFormatter.java:233)
    at org.slf4j.helpers.MessageFormatter.arrayFormat(MessageFormatter.java:173)
    at org.eclipse.jetty.util.log.JettyAwareLogger.log(JettyAwareLogger.java:680)
    at org.eclipse.jetty.util.log.JettyAwareLogger.debug(JettyAwareLogger.java:224)
    at org.eclipse.jetty.util.log.Slf4jLog.debug(Slf4jLog.java:97)
    at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.doProduce(EatWhatYouKill.java:288)
    at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.tryProduce(EatWhatYouKill.java:168)
    at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.run(EatWhatYouKill.java:126)
    at org.eclipse.jetty.util.thread.ReservedThreadExecutor$ReservedThread.run(ReservedThreadExecutor.java:366)
    at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:765)
    at org.eclipse.jetty.util.thread.QueuedThreadPool$2.run(QueuedThreadPool.java:683)
    at java.lang.Thread.run(Thread.java:748)

SLF4J: Failed toString() invocation on an object of type [org.eclipse.jetty.util.thread.strategy.EatWhatYouKill]
Reported exception:
java.lang.NoClassDefFoundError: org/eclipse/jetty/io/ManagedSelector$StopSelector
    at java.lang.Class.getDeclaringClass0(Native Method)
    at java.lang.Class.getDeclaringClass(Class.java:1235)
    at java.lang.Class.getEnclosingClass(Class.java:1277)
    at java.lang.Class.getSimpleBinaryName(Class.java:1443)
    at java.lang.Class.getSimpleName(Class.java:1309)
    at org.eclipse.jetty.io.ManagedSelector$SelectorProducer.toString(ManagedSelector.java:534)
    at java.lang.String.valueOf(String.java:2994)
    at java.lang.StringBuilder.append(StringBuilder.java:131)
    at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.getString(EatWhatYouKill.java:458)
    at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.toStringLocked(EatWhatYouKill.java:447)
    at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.toString(EatWhatYouKill.java:440)
    at org.slf4j.helpers.MessageFormatter.safeObjectAppend(MessageFormatter.java:299)
    at org.slf4j.helpers.MessageFormatter.deeplyAppendParameter(MessageFormatter.java:271)
    at org.slf4j.helpers.MessageFormatter.arrayFormat(MessageFormatter.java:233)
    at org.slf4j.helpers.MessageFormatter.arrayFormat(MessageFormatter.java:173)
    at org.eclipse.jetty.util.log.JettyAwareLogger.log(JettyAwareLogger.java:680)
    at org.eclipse.jetty.util.log.JettyAwareLogger.debug(JettyAwareLogger.java:224)
    at org.eclipse.jetty.util.log.Slf4jLog.debug(Slf4jLog.java:97)
    at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.doProduce(EatWhatYouKill.java:288)
    at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.tryProduce(EatWhatYouKill.java:168)
    at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.run(EatWhatYouKill.java:126)
    at org.eclipse.jetty.util.thread.ReservedThreadExecutor$ReservedThread.run(ReservedThreadExecutor.java:366)
    at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:765)
    at org.eclipse.jetty.util.thread.QueuedThreadPool$2.run(QueuedThreadPool.java:683)
    at java.lang.Thread.run(Thread.java:748)
Caused by: java.lang.ClassNotFoundException: Illegal access: this web application instance has been stopped already. Could not load [org.eclipse.jetty.io.ManagedSelector$StopSelector]. The following stack trace is thrown for debugging purposes as well as to attempt to terminate the thread which caused the illegal access.
    at org.apache.catalina.loader.WebappClassLoaderBase.checkStateForClassLoading(WebappClassLoaderBase.java:1338)
    at org.apache.catalina.loader.WebappClassLoaderBase.loadClass(WebappClassLoaderBase.java:1195)
    at org.apache.catalina.loader.WebappClassLoaderBase.loadClass(WebappClassLoaderBase.java:1157)
    ... 25 more
Caused by: java.lang.IllegalStateException: Illegal access: this web application instance has been stopped already. Could not load [org.eclipse.jetty.io.ManagedSelector$StopSelector]. The following stack trace is thrown for debugging purposes as well as to attempt to terminate the thread which caused the illegal access.
    at org.apache.catalina.loader.WebappClassLoaderBase.checkStateForResourceLoading(WebappClassLoaderBase.java:1348)
    at org.apache.catalina.loader.WebappClassLoaderBase.checkStateForClassLoading(WebappClassLoaderBase.java:1336)
    ... 27 more
27-Dec-2018 11:24:20.467 INFO [jetty-http@74305db9-65] org.apache.catalina.loader.WebappClassLoaderBase.checkStateForResourceLoading Illegal access: this web application instance has been stopped already. Could not load [ch.qos.logback.classic.spi.ThrowableProxy]. The following stack trace is thrown for debugging purposes as well as to attempt to terminate the thread which caused the illegal access.
 java.lang.IllegalStateException: Illegal access: this web application instance has been stopped already. Could not load [ch.qos.logback.classic.spi.ThrowableProxy]. The following stack trace is thrown for debugging purposes as well as to attempt to terminate the thread which caused the illegal access.
    at org.apache.catalina.loader.WebappClassLoaderBase.checkStateForResourceLoading(WebappClassLoaderBase.java:1348)
    at org.apache.catalina.loader.WebappClassLoaderBase.checkStateForClassLoading(WebappClassLoaderBase.java:1336)
    at org.apache.catalina.loader.WebappClassLoaderBase.loadClass(WebappClassLoaderBase.java:1195)
    at org.apache.catalina.loader.WebappClassLoaderBase.loadClass(WebappClassLoaderBase.java:1157)
    at ch.qos.logback.classic.spi.LoggingEvent.<init>(LoggingEvent.java:119)
    at ch.qos.logback.classic.Logger.buildLoggingEventAndAppend(Logger.java:419)
    at ch.qos.logback.classic.Logger.filterAndLog_0_Or3Plus(Logger.java:383)
    at ch.qos.logback.classic.Logger.log(Logger.java:765)
    at org.eclipse.jetty.util.log.JettyAwareLogger.log(JettyAwareLogger.java:668)
    at org.eclipse.jetty.util.log.JettyAwareLogger.warn(JettyAwareLogger.java:474)
    at org.eclipse.jetty.util.log.Slf4jLog.warn(Slf4jLog.java:73)
    at org.eclipse.jetty.util.log.Slf4jLog.warn(Slf4jLog.java:67)
    at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.execute(EatWhatYouKill.java:375)
    at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.doProduce(EatWhatYouKill.java:305)
    at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.tryProduce(EatWhatYouKill.java:168)
    at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.run(EatWhatYouKill.java:126)
    at org.eclipse.jetty.util.thread.ReservedThreadExecutor$ReservedThread.run(ReservedThreadExecutor.java:366)
    at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:765)
    at org.eclipse.jetty.util.thread.QueuedThreadPool$2.run(QueuedThreadPool.java:683)
    at java.lang.Thread.run(Thread.java:748)

Exception in thread "jetty-http@74305db9-65" java.lang.NoClassDefFoundError: ch/qos/logback/classic/spi/ThrowableProxy
    at ch.qos.logback.classic.spi.LoggingEvent.<init>(LoggingEvent.java:119)
    at ch.qos.logback.classic.Logger.buildLoggingEventAndAppend(Logger.java:419)
    at ch.qos.logback.classic.Logger.filterAndLog_0_Or3Plus(Logger.java:383)
    at ch.qos.logback.classic.Logger.log(Logger.java:765)
    at org.eclipse.jetty.util.log.JettyAwareLogger.log(JettyAwareLogger.java:668)
    at org.eclipse.jetty.util.log.JettyAwareLogger.warn(JettyAwareLogger.java:474)
    at org.eclipse.jetty.util.log.Slf4jLog.warn(Slf4jLog.java:73)
    at org.eclipse.jetty.util.log.Slf4jLog.warn(Slf4jLog.java:67)
    at org.eclipse.jetty.util.thread.QueuedThreadPool$2.run(QueuedThreadPool.java:740)
    at java.lang.Thread.run(Thread.java:748)

> < li>

如何避免这种异常?

有没有其他方法可以改善WebClient首次请求速度慢的问题?

共有1个答案

凌嘉勋
2023-03-14

我们将Spring Boot升级到2.4.2,使用rearmer-netty 1.0.3,但仍然遇到此问题。以下是我们的升级配置:

   @Bean
    public WebClient createWebClient(WebClient.Builder webClientBuilder) {
        log.info("Initializing WebClient Bean");

        final int timeoutInMillis = Long.valueOf(TimeUnit.SECONDS.toMillis(timeout)).intValue();
        final HttpClient httpClient = HttpClient.create()
                .option(ChannelOption.CONNECT_TIMEOUT_MILLIS, timeoutInMillis)
                .responseTimeout(Duration.ofMillis(timeoutInMillis))
                .doOnConnected(conn ->
                        conn.addHandlerLast(new ReadTimeoutHandler(timeoutInMillis, TimeUnit.MILLISECONDS))
                                .addHandlerLast(new WriteTimeoutHandler(timeoutInMillis, TimeUnit.MILLISECONDS)));
        final ClientHttpConnector connector = new ReactorClientHttpConnector(httpClient);
        final WebClient webClient = webClientBuilder
                .clientConnector(connector)
                .defaultHeader("x-clientname", clientname)
                .build();

        httpClient.warmup().block();
        log.info("WebClient initialized");

        return webClient;
    }

我们与WebClient的通话:

  ResoponseObject doCall() {
        return this.webClient
                .get()
                .uri("http://***.de/api/rest/***")
                .accept(MediaType.APPLICATION_JSON)
                .retrieve()
                .bodyToMono(ResponseObject.class)
                .block();
    }

通过 application.yaml 启用调试:logging.level.reactor.netty:debug

我们现在在应用程序启动期间看到这种情况:

2021-02-10 17:02:31,922 INFO  d.t.e.b.c.c.WebClientAutoConfiguration - Initializing WebClient Bean 
2021-02-10 17:02:31,959 DEBUG r.n.r.DefaultLoopIOUring - Default io_uring support : false 
2021-02-10 17:02:31,967 DEBUG r.n.r.DefaultLoopEpoll - Default Epoll support : true 
2021-02-10 17:02:31,997 INFO  d.t.e.b.c.c.WebClientAutoConfiguration - WebClient initialized 

这应该是预热按预期工作的迹象?

但在第一次请求时会发生这种情况:

2021-02-10 17:05:16,045 DEBUG o.s.w.r.f.c.ExchangeFunctions - [73d400c8] HTTP GET http://***.de/api/rest/***
2021-02-10 17:05:16,050 DEBUG r.n.r.PooledConnectionProvider - Creating a new [http] client pool [PoolFactory{evictionInterval=PT0S, leasingStrategy=fifo, maxConnections=500, maxIdleTime=-1, maxLifeTime=-1, metricsEnabled=false, pendingAcquireMaxCount=1000, pendingAcquireTimeout=45000}] for [***.de/<unresolved>:80] 
2021-02-10 17:05:29,619 DEBUG r.n.r.DefaultPooledConnectionProvider - [id: 0x71b840f4] Created a new pooled channel, now 1 active connections and 0 inactive connections 
2021-02-10 17:05:29,635 DEBUG r.n.t.TransportConfig - [id: 0x71b840f4] Initialized pipeline DefaultChannelPipeline{(reactor.left.httpCodec = io.netty.handler.codec.http.HttpClientCodec), (reactor.right.reactiveBridge = reactor.netty.channel.ChannelOperationsHandler)} 
...

在我们的例子中,创建客户机池是问题所在。在一台像样的机器上,大约需要13秒。

你能给我们一些评论吗?这对我们来说非常令人沮丧。

谢谢!

 类似资料:
  • 本文向大家介绍ASP.NET网站第一次访问慢的解决方法,包括了ASP.NET网站第一次访问慢的解决方法的使用技巧和注意事项,需要的朋友参考一下 本篇经验以IIS8,Windows Server 2012R2做为案例。 IIS8 运行在Windows Server 2012 and Windows 8 版本以上的平台上。 IIS中应用程序池和网站是单独存在的,但是网站运行必须建立在对应的应用程序池启

  • 本文向大家介绍docker容器内网络请求缓慢问题解决,包括了docker容器内网络请求缓慢问题解决的使用技巧和注意事项,需要的朋友参考一下 在使用docker的过程中发现了几个问题,在docker里进行的网络请求经常会失败,比如npm install以及bundle install等操作,或者是作为中间层在应用中去获取api数据的过程经常会出现timeout等情况,所以开始探究docker的网络机

  • 本文向大家介绍ASP.NET第一次访问慢的完美解决方案(MVC,Web Api),包括了ASP.NET第一次访问慢的完美解决方案(MVC,Web Api)的使用技巧和注意事项,需要的朋友参考一下 问题现象 访问asp.net web项目的时候,第一次访问比较慢,当闲置一段时间后,再次访问还是会非常慢。 问题原因 这是IIS回收造成的,再次访问的时候会初始化操作,初始化需要耗费时间,所以访问会比较慢

  • 本文向大家介绍按钮的Ajax请求时一次点击两次提交的解决方法,包括了按钮的Ajax请求时一次点击两次提交的解决方法的使用技巧和注意事项,需要的朋友参考一下 页面中的按钮的type是submit的: <input type="submit" value="Create" id="submit" /> ajax的请求,在JQuery中是: 发生两次提交的原因是在执行完ajax请求后,并没有阻止subm

  • 我不熟悉vertx和RxJava。我正在尝试实现一个简单的测试程序。然而,我无法理解这个项目的动态。为什么有些请求需要10秒钟以上才能响应? 下面是我的示例测试应用程序 我想知道的是,是什么让我的响应时间变慢了?

  • 我是反应性编程的新手,我正在使用Spring WebFlux的WebClient向下面的URL发出POST请求,作为Spring Boot应用程序的一部分,将现有的测验分配给候选人。我很难理解我在构造WebClient请求时做错了什么。 终点 quizrequest.java java FlexiQuizClient.java 在我的资源类(控制器)中,我调用web客户端方法,如下所示: 示例响应