spring-webflux - Spring Webflux - 服务器/客户端线程利用率
问题描述
我正在使用 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:8080/1 进行了 4 次调用并得到以下输出。只有一个请求设法到达第三种方法。我预计当一个线程被阻塞时,其他三个将能够处理其他请求,但他们没有。整个线程池由 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]
你能解释一下这种行为吗?
- - - - 编辑 - - - -
说明: https ://groups.google.com/forum/#!topic/netty/1kAS-FJWGRE
解决方案
您已经知道这一点,但其他开发人员正在阅读:您不应该在 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]
推荐阅读
- python - 使用熊猫为具有特定条件的每一行设置列值
- python - python - ImportError:无法导入名称 wsgiserver
- angular - 无法在 mat-dialog-content 中放置 mat-grid-list 和 mat-list
- javascript - Firebase 身份验证无法使用 Vue 和 Vuex
- c# - 比奈公式
- snakemake - 即使缺少某些输入,如何运行规则?
- r - 如何使用变量名创建未知深度列表?
- html - 为什么没有填充或边距时文本似乎有填充?
- autodesk-forge - Forge Viewer 切割模型 Level Wise
- echarts - Apache ECharts 地图很奇怪(非常基本的问题)