首页 文章

Spring Webflux - 服务器/客户端线程利用率

提问于
浏览
1

我正在和Netty一起使用Spring Webflux(2.0.3.RELEASE),并尝试了解服务器和Web客户端如何使用线程 . 我用WebClient编写了一些带有http调用链的代码片段 . 我怀疑所有的呼叫都是非阻塞的,但我无法弄清楚为什么只有一个请求通过整个链 . 这是下面的代码和日志输出:

public class DemoApplication {

private WebClient webclient = WebClient.create("http://localhost:8080/");

public static void main(String[] args) throws Exception {
    new DemoApplication().startServer();
}

public void startServer() throws Exception {
    RouterFunction<ServerResponse> route = routingFunction();
    HttpHandler httpHandler = RouterFunctions.toHttpHandler(route);
    ReactorHttpHandlerAdapter adapter = new ReactorHttpHandlerAdapter(httpHandler);
    HttpServer server = HttpServer.create("127.0.0.1", 8080);
    server.newHandler(adapter).block();
    Thread.sleep(1000000);
}

public RouterFunction<ServerResponse> routingFunction() throws Exception {
    return route(path("/1"), req -> ok().body(fromPublisher(get1(), String.class)))
            .andRoute(path("/2"), req -> ok().body(fromPublisher(get2(), String.class)))
            .andRoute(path("/3"), req -> ok().body(fromPublisher(get3(), String.class)));
}

public Mono<String> get1() {
    System.out.println("---------REQUEST---------");
    System.out.println("1: " + Thread.currentThread());
    return webclient.get().uri("2").retrieve().bodyToMono(String.class);
}

public Mono<String> get2() {
    System.out.println("2: " + Thread.currentThread());
    return webclient.get().uri("3").retrieve().bodyToMono(String.class);
}

public Mono<String> get3() {
    System.out.println("3: " + Thread.currentThread());
    try {
        Thread.sleep(1250000); // simulate thread somehow got blocked
    } catch (InterruptedException e) {

    }
    return Mono.just("test");
}
}

我对localhost进行了4次调用:8080/1并得到以下输出 . 只有一个请求设法达到第三种方法 . 我预计当一个线程被阻塞时,其他三个将能够处理其他请求,但他们没有 . 整个线程池由4个线程组成(与核心数相同) .

---------REQUEST---------
1: Thread[reactor-http-nio-2,5,main]
2: Thread[reactor-http-nio-4,5,main]
3: Thread[reactor-http-nio-2,5,main]
---------REQUEST---------
1: Thread[reactor-http-nio-3,5,main]
2: Thread[reactor-http-nio-1,5,main]
---------REQUEST---------
1: Thread[reactor-http-nio-3,5,main]
2: Thread[reactor-http-nio-1,5,main]
---------REQUEST---------
1: Thread[reactor-http-nio-3,5,main]
2: Thread[reactor-http-nio-1,5,main]

你能解释一下这种行为吗?

--------EDIT-------

说明:https://groups.google.com/forum/#!topic/netty/1kAS-FJWGRE

1 回答

  • 1

    您已经知道了,但是其他开发人员读到这一点:您永远不应该在Reactor应用程序中使用阻塞操作 - 或者如果您这样做,您应该在弹性 Scheduler 上安排该工作,并注意权衡 .

    如果您想要模拟远程服务需要很长时间才能响应,您可以使用 delay* 运算符,而无需人工阻塞线程 . 在这种情况下,我想您想模拟应用程序的一部分在反应流水线中使用阻塞I / O这一事实 .

    我认为你在这里看到的行为与服务器调用自身的事实有关,而 WebClient 和Netty服务器共享相同的 EventLoopGroup . 在这种情况下,我不知道工作窃取的实施细节 .

    我用这样的阻塞处理程序简化了这个例子:

    @Bean
    public RouterFunction<ServerResponse> routingFunction() throws Exception {
        return route(all(), this::handler);
    }
    
    Mono<ServerResponse> handler(ServerRequest request) {
        System.out.println("---------REQUEST---------");
        System.out.println(Thread.currentThread());
        try {
            Thread.sleep(1250000); // simulate thread somehow got blocked
        } catch (InterruptedException e) {
    
        }
        return ServerResponse.ok().build();
    }
    

    在这种情况下,使用 curl 客户端调用该服务器会按预期显示以下行为(在8核笔记本电脑上) .

    ---------REQUEST---------
    Thread[reactor-http-nio-2,5,main]
    ---------REQUEST---------
    Thread[reactor-http-nio-3,5,main]
    ---------REQUEST---------
    Thread[reactor-http-nio-4,5,main]
    ---------REQUEST---------
    Thread[reactor-http-nio-5,5,main]
    ---------REQUEST---------
    Thread[reactor-http-nio-6,5,main]
    ---------REQUEST---------
    Thread[reactor-http-nio-7,5,main]
    ---------REQUEST---------
    Thread[reactor-http-nio-8,5,main]
    ---------REQUEST---------
    Thread[reactor-http-nio-1,5,main]
    

相关问题