Spring Flux是一个完全非阻塞, 异步的web框架.支持和spring mvc接近的注解配置controler, 还支持functional endpoint风格的配置.
spring-webflux 依赖于reactor-core, 以此来提供异步流支持.
即使只使用mvc, 也可以使用异步的webclient, 另外Spring WebFlux是可以和Mvc同时存在于一个项目的.
异步非阻塞在性能上真正的好处是, 在高请求的情况下, 更少的内存, 更少的线程数量。
在响应式的技术体系中, 有两个非常重要的概念:
flux和mono
简单的理解: 代表一种当前不存在, 在未来某个时间可以通过其中数据来获取的一种抽象. 其中Mono代表可以获取0个或1个数据, Flux则是多个数据.
reactive就是non blocking.
支持back pressure(发送的数据不超过服务端的处理能力), 这个是需要在费阻塞编程中处理的问题.
reactive stream是致力于解决这个问题的规范.
但是reactive stream 太底层, 应用需要更加高层, 功能更加丰富的api, Spring Flux正是扮演了这个角色.
1 类似mvc的注解模型
2 函数式endpoint
不采用flux的考虑:
加入原来的应用使用spring mvc编写, 而且没有什么问题。 那么就没有必要转换未flux.
同步的代码容易编写, 理解和调试。
假如应用依赖阻塞式的类库, 如jdbc, jpa或者阻塞式的网络io, 那么其实采用flux没有什么意义。
非阻塞, 函数式和声明式编程的学习曲线并不平滑, 假如原来的架构是阻塞式的, 大范围转移是不必要的。
即使不完全使用flux, 使用异步的webClient的理由:
可以采用异步的webClient去调用远程服务, 如果当前应用是有很多这种转发调用, 那么会有很大地助益. 这种异步的客户端同时可以唤起的请求可以非常多, 并且只需要少量的线程.
如果决定要用异步的或者函数式的编程, 选择flux的理由:
spring flux, 提供服务器底层的选择(netty, servlet3.1+, tomcat, jetty, undertow等等), 编程模式的选择(接近mvc的注解controller风格, 函数式风格), 一些异步库(Reactor, RxJava等)
轻量的函数式web框架
支持netty, tomcat, jetty, undertow等服务器。 默认的服务器是netty
spring flux提供统一的高层api来屏蔽这些低层api的不同.
假如使用tomcat作为服务器, 那么如果在项目中使用servlet api, 其实并不是直接使用的, 而是经过一系列低层的adapter转换来间接使用的。
异步非阻塞一般来说并不会使应用跑得更快(除了并行用webvlient请求远程服务这种情况), 反而会因为需要做更多的工作, 而增加少量的处理时间。
异步非阻塞的关键价值, 是能更好的基于少量固定数目的线程和少量的内存下进行伸缩(这里的伸缩是指处理的数据规模的放大和缩小)。 这让程序更加有弹性, 因为它能以更加可预测的方式进行伸缩。(这一句我不理解)
假如应用有一些如网络通信等高延迟的操作, 那么这种好处会很明显, 甚至可以非常夸张。
异步非阻塞在性能上真正的好处是, 在高请求的情况下, 更少的内存, 更少的线程数量(线程的创建和维持都是有开销的)。
spring mvc假设一个请求的处理过程可能被线程阻塞, 所以使用一个比较大的线程池
flux假设请求的处理过程中没有阻塞, 所以使用一个比较小的固定数量的线程来处理请求
假如需要在webflux调用阻塞的类库, reactor库和rxjava库都有publish操作符, 可以将这种处理在其他的线程上继续。 无论如何, 在flux中使用阻塞类库是不被推荐的。
将应用从维护可变状态的线程安全中解放出来, 因为这些是会按序执行的
对于一个没有数据库访问的webflux, 一般来说是一个线程作为server, 和cpu数量一致的线程作为处理请求。
应用有webclient调用, 少数量固定数目的线程来给wecliwnt使用, 或者如果使用netty作为服务器, 那么复用请求线程。
Reactor和rxjava有Scheduler这种线程池, 当publishon这种操作发生时, 就会在使用这种线程的线程池。 这种线程池有两种, 一种是专门处理计算复杂型的任务, 数量和cpu核数相关, 一种是专门处理io类型的任务, 这种线程的数量会比较多。
参考文档:
官方文档: docs.spring.io/spring/docs…