最近在做些系统性能瓶颈问题的提升,所以在一些开源社区以及一些著名论坛上看到针对WebFlux
的解释和说明,这里不能说不好,总体上就是阻塞-非阻塞
、性能提升
、速度更快
、支持函数式编程
、反应式编程(Reactive)
...人云亦云吗?
一 问题
这里不对一些概念性问题进行解说,主要针对一些疑问来说明?
- WebFlux 是什么?
- WebFlux 真的快吗?
- WebFlux应用场景?
二 知其然不知其所以然
2.1 Spring MVC & Spring WebFlux
我们先来了解下WebFlux
: 这是Spring.io 官网提供的解释
结合上图,Spring再解释说明Spring WebFlux
的时候与传统web开发使用的Spring MVC
模型进行了对比说明:
Spring MVC
Spring MVC is built on the Servlet API and uses a synchronous blocking I/O architecture whth a one-request-per-thread model.
- Spring MVC 构建于 Servlet API 之上,使用的是同步阻塞式 I/O 模型,什么是同步阻塞式 I/O 模型呢?就是说,每一个请求对应一个线程去处理。
这里重点提示一下:
- 基于Servlet Contatiners 阻塞式I/O模型;
-
a one-request-per-thread model
意思就是说:一个请求对应一个线程去处理。
Spring WebFlux
Spring WebFlux is a non-blocking web framework built from the ground up to take advantage of multi-core, next-generation processors and handle massive numbers of concurrent connections
Spring WebFlux 是一个异步非阻塞式的 Web 框架,它能够充分利用多核 CPU 的硬件资源去处理大量的并发请求。
2.2 Spring WebFlux
The original web framework included in the Spring Framework, Spring Web MVC, was purpose-built for the Servlet API and Servlet containers. The reactive-stack web framework, Spring WebFlux, was added later in version 5.0. It is fully non-blocking, supports Reactive Streams back pressure, and runs on such servers as Netty, Undertow, and Servlet 3.1+ containers.
Spring框架中包含的原始Web框架, Spring Web MVC是专门为Servlet API和Servlet容器而构建的。反应性堆栈Web框架Spring WebFlux在更高版本5.0中添加。它是完全非阻塞的,支持 Reactive Streams背压,并在Netty,Undertow和Servlet 3.1+容器等服务器上运行。
2.2 Why was Spring WebFlux created?
以下说明来源于官网
- Part of the answer is the need for a non-blocking web stack to handle concurrency with a small number of threads and scale with fewer hardware resources. Servlet 3.1 did provide an API for non-blocking I/O. However, using it leads away from the rest of the Servlet API, where contracts are synchronous (
Filter
,Servlet
) or blocking (getParameter
,getPart
). This was the motivation for a new common API to serve as a foundation across any non-blocking runtime. That is important because of servers (such as Netty) that are well-established in the async, non-blocking space.
简单解释说明一下
- 就是说一部分原因需要一个非阻塞的web堆栈来处理少量线程的并发性,并使用较少的硬件资源进行扩展。Servlet 3.1确实提供了用于非阻塞I / O的API。但是其中约定是同步的诸如(
Filter
、Servlet
)以及阻塞的(getParameter
、getPart
),所以使用Servlet 3.1可能会导致不在使用Servlet API 其他部分。这也同样的会促进一个新的通用性的API在任何非阻塞提供一个基础的时机。诸如:服务器(如Netty)在异步、非阻塞空间中已经很好地建立起来。
提炼
- 异步非阻塞(non-blocking web stack)
- 少量线程数处理并发性(handle concurrency with a small number of threads)
- 少量硬件资源提高伸缩性(scale with fewer hardware resources.)
- Servlet 3.1 提供一个非阻塞API。
- The other part of the answer is functional programming. Much as the addition of annotations in Java 5 created opportunities (such as annotated REST controllers or unit tests), the addition of lambda expressions in Java 8 created opportunities for functional APIs in Java. This is a boon for non-blocking applications and continuation-style APIs (as popularized by
CompletableFuture
and ReactiveX) that allow declarative composition of asynchronous logic. At the programming-model level, Java 8 enabled Spring WebFlux to offer functional web endpoints alongside annotated controllers.
简单解释说明一下
- 另一部分原因:函数式编程。与在Java5中添加注释创造了机会(如带注释的REST控制器或单元测试)一样,在Java8中添加lambda表达式也为Java中的功能性API创造了机会。这对于非阻塞的应用程序和允许异步逻辑的声明式组合的 (as popularized by
CompletableFuture
and ReactiveX) 是有益的。在编程模型级别,Java 8支持Spring WebFlux提供功能性的web端点和带注释的控制器。
提炼
- 函数式编程(functional programming)
- 反应式(Reactive)
了解以上背景后再说说什么是``Reactive`
- The term, “reactive,” refers to programming models that are built around reacting to change — network components reacting to I/O events, UI controllers reacting to mouse events, and others. In that sense, non-blocking is reactive, because, instead of being blocked, we are now in the mode of reacting to notifications as operations complete or data.
- 反应式是指围绕对变化作出反应的编程模型,网络组件对I/O事件作出反应,UI控制器对鼠标事件作出反应,以及其他。从这个意义上说,非阻塞是被动的,因为不是被阻断,而是以操作完成或者数据的形式响应通知。
2.3 WebFlux 的优势&提升性能?
犹如上面介绍:WebFlux 内部使用的是响应式编程(Reactive Programming),以 Reactor 库为基础, 基于异步和事件驱动,可以让我们在不扩充硬件资源的前提下,提升系统的吞吐量和伸缩性。
所以它最终解决的是在很少或者不扩充硬件资源的前提下,提升系统的吞吐量和伸缩性。而不是使得应用程序运行的更快,更不会使得你的接口的请求响应的时间缩短了
下面是官网原文:
- Performance has many characteristics and meanings.
Reactive and non-blocking generally do not make applications run faster
. They can, in some cases, (for example, if using theWebClient
to execute remote calls in parallel). On the whole, it requires more work to do things the non-blocking way and that can increase slightly the required pro - WebFlux 并不能使接口的响应时间缩短,它仅仅能够提升吞吐量和伸缩性
- The key expected benefit of reactive and non-blocking is the ability to scale with a small, fixed number of threads and less memory.That makes applications more resilient under load, because they scale in a more predictable way.
- 反应式和非阻塞的主要预期好处是能够使用少量、固定数量的线程和较少的内存进行扩展。这使应用程序在负载下更具弹性,因为它们以更可预测的方式扩展。
三 WebFlux 应用场景
上面说到了, Spring WebFlux 是一个异步非阻塞式的 Web 框架,所以,它特别适合应用在 IO 密集型的服务中,比如微服务网关这样的应用中(Spring cloud gateway)。
3.1 Applicability : WebFlux OR Spring MVC?
官网给出了这么一句话:
Spring MVC or WebFlux?
A natural question to ask but one that sets up an unsound dichotomy. Actually, both work together to expand the range of available options. The two are designed for continuity and consistency with each other, they are available side by side, and feedback from each side benefits both sides. The following diagram shows how the two relate, what they have in common, and what each supports uniquely:通过这段是我们可以知道,当你问出这个问题的时候,其实这个问题本身就是已经不合理了,所以无论是WebFlux OR Spring MVC 两者设计旨在实现彼此的连续性和一致性,它们是可以并行使用。共同努力扩大了可用选型的范围。
3.2 Concurrency Model ( Spring MVC and Spring WebFlux)
Both Spring MVC and Spring WebFlux support annotated controllers, but there is a key difference in the concurrency model and the default assumptions for blocking and threads.(Spring MVC和Spring WebFlux都支持带注释的控制器,但是并发模型以及阻塞和线程的默认假设存在关键差异。)
In Spring MVC (and servlet applications in general), it is assumed that applications can block the current thread, (for example, for remote calls), and, for this reason, servlet containers use a large thread pool to absorb potential blocking during request handling.(在Spring MVC(通常是Servlet应用程序)中,假定应用程序可以阻塞当前线程(例如,用于远程调用),因此,servlet容器使用大线程池来吸收请求期间的潜在阻塞。处理。)
In Spring WebFlux (and non-blocking servers in general), it is assumed that applications do not block, and, therefore, non-blocking servers use a small, fixed-size thread pool (event loop workers) to handle requests.(在Spring WebFlux(通常是非阻塞服务器)中,假定应用程序未阻塞,因此,非阻塞服务器使用固定大小的小型线程池(事件循环工作器)来处理请求。)
下图是两者的共同点和独自的特性
官网也提出了很多关于这方面的建议:
We suggest that you consider the following specific points:
* 如果您有运行正常的Spring MVC应用程序,则无需更改。命令式编程是编写,理解和调试代码的最简单方法。您有最大的库选择空间,大多数都处于阻塞状态。
* 如果您已经在购买无阻塞Web堆栈,那么Spring WebFlux在此空间中提供的执行模型优势与其他模型相同,并且还提供服务器选择(Netty,Tomcat,Jetty,Undertow和Servlet 3.1+容器),选择编程模型(带注释的控制器和功能性Web端点),以及选择反应式库(Reactor,RxJava或其他).
* 如果您对与Java 8 lambda或Kotlin一起使用的轻量级功能性Web框架感兴趣,可以使用Spring WebFlux功能性Web端点。对于要求较低复杂性的较小应用程序或微服务(可以受益于更高的透明度和控制)而言,这也是一个不错的选择.
* 在微服务架构中,您可以混合使用带有Spring MVC或Spring WebFlux控制器或带有Spring WebFlux功能端点的应用程序。在两个框架中都支持相同的基于注释的编程模型,这使得重用知识变得更加容易,同时还为正确的工作选择了正确的工具.
* 评估应用程序的一种简单方法是检查其依赖关系。如果您要使用阻塞性持久性API(JPA,JDBC)或网络API,则Spring MVC至少是常见体系结构的最佳选择。在Reactor和RxJava上在单独的线程上执行阻塞调用在技术上都是可行的,但是您不会充分利用非阻塞Web堆栈.
* 如果您的Spring MVC应用程序具有对远程服务的调用,请尝试使用active `WebClient`。您可以直接从Spring MVC控制器方法返回反应性类型(Reactor,RxJava [或其他]每个呼叫的等待时间或呼叫之间的相互依赖性越大,好处就越明显。Spring MVC控制器也可以调用其他反应式组件.
* 如果您有庞大的团队,请牢记向无阻塞,功能性和声明性编程的过渡过程中的学习曲线陡峭。在没有完全切换的情况下启动的实际方法是使用电抗器`WebClient`。除此之外,从小处着手并衡量收益。我们希望,对于广泛的应用程序,这种转变是不必要的。如果不确定要寻找什么好处,请先了解无阻塞I / O的工作原理(例如,单线程Node.js上的并发性)及其影响.