Reactive Programming
一种以异步处理数据流为中心思想的编程范式,这个范式存在已久,不是新概念,就像面向过程、面向对象编程、函数式编程等范式。
对比一下,Reactive streams指的是一套规范,对于Java开发者来讲,Reactive Streams就是一套API,使我们可以进行Reactive programming。
Reactive模型最核心的是线程和消息管道。线程用于侦听事件,消息管道用于线程之间通信不同的消息。
Reactive Manifesto。一切反应式概念的根源理论基础。
https://www.reactivemanifesto.org/zh-CN
描述了反应式系统(reactive systems)应该具备的四个关键属性:Responsive(灵敏的)、Resilient(可故障恢复的)、Elastic(可伸缩的)、Message Driven(消息驱动的)。
指令式编程 vs 反应式(响应式)编程
from 维基百科
以汽车?来举例,
java8 时代的开源jar包,在java9时代被正式引入java api。
官网:https://www.reactive-streams.org/
github:https://github.com/reactive-streams/reactive-streams-jvm/blob/v1.0.3/README.md
简介
Reactive Streams is an initiative to provide a standard for asynchronous stream processing with non-blocking back pressure. This encompasses efforts aimed at runtime environments (JVM and JavaScript) as well as network protocols.
目标、设计与适用范围
Handling streams of data—especially “live” data whose volume is not predetermined—requires special care in an asynchronous system. The most prominent issue is that resource consumption needs to be carefully controlled such that a fast data source does not overwhelm the stream destination. Asynchrony is needed in order to enable the parallel use of computing resources, on collaborating network hosts or multiple CPU cores within a single machine.
The main goal of Reactive Streams is to govern the exchange of stream data across an asynchronous boundary – think passing elements on to another thread or thread-pool — while ensuring that the receiving side is not forced to buffer arbitrary amounts of data. In other words, backpressure is an integral part of this model in order to allow the queues which mediate between threads to be bounded.
In summary, Reactive Streams is a standard and specification for Stream-oriented libraries for the JVM that
- process a potentially unbounded number of elements
- in sequence,
- asynchronously passing elements between components,
- with mandatory non-blocking backpressure.
总之,反应流是jvm上面向流的库的一个标准和规范:
jdk9中集成,由reactive-stream-jvm发展而来。
The interfaces available in JDK9’s java.util.concurrent.Flow, are 1:1 semantically equivalent to their respective Reactive Streams counterparts. This means that there will be a migratory period, while libraries move to adopt the new types in the JDK, however this period is expected to be short - due to the full semantic equivalence of the libraries, as well as the Reactive Streams <-> Flow adapter library as well as a TCK compatible directly with the JDK Flow types.
jdk9中的java.util.concurrent.Flow是对Reactive Streams的完全对等实现,除了类名不同以外其他部分都可以做一对一迁移。
Jdk9的Reactive Stream API(java.util.concurrent.Flow)只是一套接口,约定了Reactive编程的一套规范,并没有具体的实现。而实现了这个接口的产品有:RxJava、Reactor、Akka等,而Spring WebFlux中集成的是Reactor3.0。
目前 Java 平台上主流的反应式库有两个,分别是 Netflix 维护的 RxJava 和 Pivotal 维护的 Reactor。RxJava 是 Java 平台反应式编程的鼻祖。反应式流规范在很大程度上借鉴了 RxJava 的理念。
由于 RxJava 的产生早于反应式流规范,与规范的兼容性并不是特别好。
ReactiveX最初被微软应用在.NET上,而后慢慢的在衍生出了各种不同语言的实现,诸如RxSwift/RxJava/RxJS。
Rx提供了一种新的组织和协调异步事件的方式,极大的简化了代码的编写。Rx最显著的特性是使用可观察集合(Observable Collection)来达到集成异步(composing asynchronous)和基于事件(event-based)的编程的效果。
RxJava:https://github.com/ReactiveX/RxJava
以RxJS角度分析Reactive Programming:https://blog.techbridge.cc/2016/05/28/reactive-programming-intro-by-rxjs/
一种反应式编程框架。
有两种模型,Flux 和 Mono,提供了非阻塞、支持回压机制的异步流处理能力。当数据生成缓慢时,整个流自然进入推送模式;而当生产高峰来临数据生产速度加快时,整个流又进入了拉取模式。Flux 可以触发 0 到多个事件,用于异步地处理流式的信息;Mono 至多可以触发一个事件,通常用于在异步任务完成时发出通知。Flux 和 Mono 之间可以相互转换。对一个 Flux 序列进行计数操作,得到的结果是一个 Mono对象,把两个 Mono 序列合并在一起,得到的是一个 Flux 对象。
Spring5.0的新模块,基于Reactor框架。包含了反应式HTTP和WebSocket的支持。上层编程模型同时支持SpringMVC中基于Java注解方式以及Java8的lambda表达式的函数式编程模型。只在编码方式不同,运行时效果相同都在反应式底层架构之上。
webflux的关键是自己编写的代码里面返回流(Flux/Mono),spring框架来负责处理订阅。
与传统 Spring MVC 的区别在于,WebFlux 的请求和响应使用的都是 Flux 或 Mono 对象。一般的 REST API 使用 Mono 来表示请求和响应对象;服务器推送事件使用 Flux 来表示从服务器端推送的事件流;WebSocket 则使用 Flux 来表示客户端和服务器之间的双向数据传递。
为了最大程度的发挥反应式流和负压的作用,WebFlux 应用的各个部分都应该是支持反应式的,也就是说各个部分都应该是异步非阻塞的。要做到这一点,需要其他的库提供支持,主要是与外部系统和服务整合的部分。
比如在数据访问层,可以通过 Spring Data 的反应式支持来访问不同类型的数据源。当然这也需要底层驱动的支持。越来越多的数据源驱动已经提供了对反应式流规范的支持,还有很多开源库可以使用。
https://doc.akka.io/docs/akka/current/typed/guide/introduction.html
一个基于反应式编程理念的全异步、高并发、可容错的事件驱动编程框架,构建于JVM上,支持java和scala开发。
Actors 为你提供:
容错性
位置透明性
Akka的所有元素都为分布式环境而设计:所有actor只通过发送消息进行交互,所有操作都是异步的。
持久性
actor接收到的消息可以选择性的被持久化,并在actor启动或重启的时候重放。这使得actor能够恢复其状态,即使是在JVM崩溃或正在迁移到另外节点的情况下。
了解了反应式编程原理,那使用反应式编程设计的优势和劣势是什么呢?
StackOverflow上有相关话题讨论
https://stackoverflow.com/questions/42062199/reactive-programming-advantages-disadvantages
上个月《大型网站技术架构:核心原理与案例分析》的作者,目前腾讯云TVP李智慧刚在infoQ发表的文章
介绍了基于Akka开发的全异步反应式框架Flower https://github.com/zhihuili/Flower
文章中提供了理论依据以及相关性能优化测试数据。
Flower 支持异步数据库驱动,用户请求数据库的时候,将请求提交给异步数据库驱动,立刻就返回,不会阻塞当前线程,异步数据库访问连接远程的数据库,进行真正的数据库操作,得到结果以后,将结果以异步回调的方式发送给 Flower 的 Service 进行进一步的处理,这个时候依然不会有线程被阻塞。也就是说使用 Flower 开发的系统,在一个典型的 Web 应用中,几乎没有任何地方会被阻塞,所有的线程都可以被不断的复用,有限的线程就可以完成大量的并发用户请求,从而大大地提高了系统的吞吐能力和响应时间,同时,由于线程不会被阻塞,应用就不会因为并发量太大或者数据库处理缓慢而宕机,从而提高了系统的可用性。
全部异步化意味着更少线程切换、避免了线程阻塞,从而获得更好的执行性能。
简单的举个例子来说,以前一个线程要做A、B、C三个方法,但是C存在IO阻塞(如数据库操作),当C方法延时高时,会使系统整体在阻塞状态的线程增多,A、B方法也受影响。
但使用反应式编程概念,A、B、C三个方法都有各自的线程(或线程池)来处理,三个方法的触发使用数据流(也可称事件)串起来,则C的阻塞不会影响A、B的处理。