首页 > 解决方案 > WebFlux 使用 WebClient 来阻止 REST 调用

问题描述

我有一种情况,我可以使用阻塞 I/O 库来访问外部服务上的 REST 端点,或者在这种情况下,我可以直接使用 HttpClient 调用该 REST,例如 WebClient。现在我想知道在该库上包装调用和在弹性线程上发布它或使用 WebClient 访问端点之间是否存在任何性能差异。

这两个选项究竟是如何处理呼叫的。所以假设 webflux 使用单线程来处理请求。然后使用 WebClient 处理请求。这是否意味着线程或事件将被阻塞,直到请求接收到所有数据并将其传递回客户端?我也很感兴趣 EventLoop 是从哪里来的,它是随 WebClient 提供的,还是已经在控制器/服务层。

这是我正在考虑使用的替代方案,因为我已经拥有通过 OkHttpClient 访问该端点的库。

Mono blockingWrapper = Mono.fromCallable(() -> { 
    return /* make a remote synchronous call */ 
});
blockingWrapper = blockingWrapper.subscribeOn(Schedulers.boundedElastic());

标签: javaspringspring-webfluxproject-reactor

解决方案


当您在非 webflux 应用程序中使用 reactor 时,例如在常规 spring web 应用程序中使用 WebClient 时,reactor 框架将启动一个事件循环来处理调度程序调度的所有事件。

另一方面,如果您在完全反应式的 webflux 应用程序中运行 WebClient,则底层服务器将启动与主机上的内核一样多的事件循环。

现在我们知道了,让我们从您的示例开始。

Spring Web客户端

如果你使用它,框架会启动一个带有线程池的调度器,它可以随时自由切换调度线程。它可能使用一个线程调度flapMap,使用另一个调度线程调用rest api,它可以随意切换。当您阻止或订阅时,您将线程留给框架,它会尽可能多地优化它所拥有的。

包装阻塞调用

另一方面,如果您使用 a 包装阻塞呼叫,onSubscribe您基本上是在说when someone subscribes (or blocks) pick a single thread from the defined scheduler and use that thread all through out execution to schedule events on the event loop.

所以你最终得到的是与常规 servlet 应用程序基本相同的标准行为。

我个人的意见是使用 webclient,因为 reactor 基本上可以从您那里抽象出线程,因此它可以尽可能地做好它的事情,而您可以专注于处理业务逻辑。你基本上选择响应式编程来获得尽可能简单的高度优化的异步非阻塞代码,而无需处理异步注释、锁、闩锁、期货、线程池等。


推荐阅读