47

目前正在使用Spring 5.0.0.RC2Reactor 3.1.0.M2Spring Boot 2.0.0.M2试验反应式编程。

想知道WebFlux 和 Reactor 用于正确编码应用程序和处理可变状态的并发和线程模型。

Reactor 文档指出该库被认为与并发无关,并提到了调度程序抽象。WebFlux 文档没有提供信息。

然而,当通过 Spring Boot 使用 WebFlux 时,定义了一个线程模型。

从我的实验中,我得到了:

  • 该模型既不是 1 个事件线程,也不是 1 个事件线程 + 工作者
  • 使用了几个线程池
  • reactor-http-nio-3 ”线程:可能每个核心一个,处理传入的 HTTP 请求
  • Thread-7 ”线程:由对 MongoDB 或 HTTP 资源的异步请求使用
  • parallel-1 ”线程:每个内核一个,由 Reactor 中的 Schedulers.parallel() 创建,由延迟运算符等使用
  • 共享可变状态必须由应用程序同步
  • ThreadLocal(用于应用程序状态、MDC 日志记录等)不是请求范围的,所以不是很有趣

它是否正确 ?WebFlux 的并发和线程模型是什么:例如默认的线程池是什么?

感谢您的信息

4

1 回答 1

45

在这个问题之后,本文档确实提供了一些关于并发模型和线程的线索(但我仍然认为从多线程的角度更清晰/更好地描述场景下发生的事情将受到高度赞赏)春季新人)。

它讨论了 Spring MVC 和 Spring WebFlux 之间的区别(每个请求 1 个线程模型与事件循环):

在 Spring MVC 和一般的 servlet 应用程序中,假设应用程序可能会阻塞当前线程,例如远程调用,因此 servlet 容器使用大型线程池来吸收请求处理期间的潜在阻塞。

在 Spring WebFlux 和一般的非阻塞服务器中,假设应用程序不会阻塞,因此非阻塞服务器使用一个小的、固定大小的线程池(事件循环工作者)来处理请求。调用阻塞 API

但请注意,Spring MVC 应用程序也可能引入一些异步性(参见 Servlet 3 Async)。我建议这个演示文稿用于讨论 Servlet 3.1 NIO 和 WebFlux。

回到文档:它还表明,在使用反应流时,您可以进行一些控制:

如果您确实需要使用阻塞库怎么办?

Reactor 和 RxJava 都提供了 publishOn 操作符来继续在不同的线程上处理。

(有关这方面的更多详细信息,请参阅Reactor 中的调度

它还讨论了您在 WebFlux 应用程序中可能期望的线程(粗体是我的):

线程模型

您应该期望在运行 Spring WebFlux 的服务器上看到哪些线程?

  • 在“普通”的 Spring WebFlux 服务器上(例如,没有数据访问,也没有其他可选的依赖项),您可以期望一个线程用于服务器,而其他几个线程用于请求处理(通常与 CPU 内核的数量一样多)。然而,Servlet 容器可以从更多线程开始(例如 Tomcat 上的 10 个),以支持 servlet、阻塞 I/O 和 servlet 3.1、非阻塞 I/O 使用。
  • 反应式WebClient事件循环样式运行。因此,您会看到与此相关的少量固定数量的处理线程,例如带有 Reactor Netty 连接器的“reactor-http-nio-”。但是如果客户端和服务器都使用 Reactor Netty,则默认情况下两者将共享事件循环资源。
  • Reactor 和 RxJava 提供线程池抽象,称为Schedulers,与用于将处理切换到不同线程池的 publishOn 运算符一起使用。调度程序的名称暗示了特定的并发策略,例如“并行”用于 CPU 密集型工作与有限数量的线程,或“弹性”用于 I/O 密集型工作与大量线程。如果您看到这样的线程,则意味着某些代码正在使用特定的线程池调度程序策略。
  • 数据访问库和其他第 3 方依赖项也可以创建和使用它们自己的线程

部分可以通过配置来配置线程模型的细节

要为服务器配置线程模型,您需要使用特定于服务器的配置 API,或者如果使用 Spring Boot,请检查每个服务器的 Spring Boot 配置选项。WebClient 可以直接配置。对于所有其他库,请参阅它们各自的文档。

此外,例如讨论 Spring boot 2.0 反应式 webflux 配置中的默认线程数 突出显示,

请求处理的默认线程数由底层 Web 服务器决定;默认情况下,Spring Boot 2.0 使用的是 Reactor Netty,它使用的是 Netty 的默认值

这是默认组件及其默认值(以及整体配置,包括通过注释透明注入的配置)的问题——这也可能在 Spring/Boot 的版本和相应的依赖项之间发生变化。说了这么多,你的猜测似乎是正确的。

于 2018-06-02T10:29:52.703 回答