繁体   English   中英

如何在Spring Web MVC控制器中利用非阻塞请求

[英]How to take advantage of non-blocking requests in Spring Web MVC Controllers

我试图证明在Spring MVC中使用响应流的优势。 为此,我有一台运行有两个端点的小型Jetty服务器:

  • /normal返回一个POJO
  • /flux返回包裹在Mono的相同对象

然后,我启动一个客户端,并在这些端点之一中发起数千个同时请求。 我希望第二个端点出现的错误更少,因为第二个端点是异步处理的。 但是,有时我会在启用了异步的端点上看到更多错误; 在这两种情况下,都会Connection refused: no further information 60- 90%的Connection refused: no further information错误Connection refused: no further information

我在这里做错了,或者我不太明白。 Connection refused只是我希望避免的那种事情。

服务器

这是我来自服务器的代码。 normal情况下,我实际上使用.sleep()阻塞线程:

@Controller
public class FluxController {
    @GetMapping(value = "/normal", produces = MediaType.APPLICATION_JSON_VALUE)
    public Map normal() throws Exception {
        Thread.sleep(randomTime());
        return Collections.singletonMap("type", "normal");
    }

    @GetMapping(value = "/flux", produces = MediaType.APPLICATION_JSON_VALUE)
    public Mono<Map> flux() {
        return Mono.delay(Duration.ofMillis(randomTime()))
                .map(x -> Collections.singletonMap("type", "flux"));
    }

    private static long randomTime() {
        return ThreadLocalRandom.current().nextLong(200, 1000);
    }
}

该服务器通过Maven在Jetty 9.4.15上运行,并且web.xml定义为:

<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
                             http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" version="3.1">

客户

我的客户使用Spring WebClient:

public class ClientApplication {

    private static final String ENDPOINT = "normal";

    private static final int REPETITIONS = 10_000;

    public static void main(String[] args) {
        WebClient client = WebClient.create("http://localhost:8080");

        AtomicInteger errors = new AtomicInteger(0);

        List<Mono<Response>> responses = IntStream.range(0, REPETITIONS)
                .mapToObj(i -> client.get()
                        .uri(ENDPOINT)
                        .retrieve()
                        .bodyToMono(Response.class)
                        .doOnError(e -> errors.incrementAndGet())
                        .onErrorResume(e -> Mono.empty())
                )
                .collect(Collectors.toList());
        Mono.when(responses)
                .block();
        System.out.println(String.format("%-2f %% errors", errors.get() * 100.0 / REPETITIONS));
    }

    static class Response {
        public String type;
    }

}

与此处问题类似的前提: WebFlux异步处理 主要区别在于我正在测试错误率或同步连接数。 我不希望速度增加。

事实证明,尽管Servlet 3.1规范支持非阻塞IO,但Spring MVC却不支持。 要充分利用反应式API,必须使用WebFlux。 请参阅此处以获取更多信息: https : //youtu.be/Dp_aJh-akkU?t=1738

此图演示了与Webflux(右侧)相比,Spring MVC(左侧)如何工作。

Spring MVC与Webflux堆栈

我使用加特林(Gatling)进行了更多测试,结果相似:两者花费的时间大致相同,异步的可靠性稍差。 但是,我确实注意到一个半可复制的差异:异步结果有时响应更快:

正常

返回标准类型时的响应时间分布

50%:33.6 s 95%:35.4 s

反应性

返回磁通时的响应时间分布

50%:6.51 s 95%:49.5 s

我仍然不清楚在Spring MVC中使用异步调用(例如DeferredResult)或Reactive Streams API的优势。 因此,如果有人能够用具体的用例来澄清这一点,将不胜感激。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM