簡體   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