Spring WebFlux和Reactor的线程模型

Flo*_*umé 23 java multithreading reactive-programming project-reactor spring-webflux

目前正在尝试使用Spring 5.0.0.RC2,Reactor 3.1.0.M2Spring Boot 2.0.0.M2进行反应式编程.

想知道WebFlux和Reactor使用的并发和线程模型来正确编写应用程序并处理可变状态.

Reactor doc声明该库被认为是并发不可知的,并提到了Scheduler抽象.WebFlux文档不提供信息.

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

从我的实验中得到的是:

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

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

感谢您的信息

met*_*ori 18

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

它讨论了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的服务器上看到哪些线程?

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

在某种程度上,您可以通过配置配置线程模型的详细信息

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

此外,例如讨论 Spring boot 2.0中的默认线程数反应webflux配置 亮点,

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

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

  • 如果我的反应式端点需要调用一个执行阻塞操作的外部非反应式端点,那么我的反应式端点仍然是反应式的吗?我使用反应式 WebClient 来调用这个外部非反应式端点 (3认同)