文章目录
- 一、为啥需要响应式程序?
- 二、响应式编程思想
- 三、实现响应式编程的探索
- 四、响应式框架历史和现状
- 历史
- 现状
- 五、响应式编程规范
一、为啥需要响应式程序?
- 传统命令式编程,在遇到需要需要外部资源的服务时,会使得当前线程进入阻塞等待。例如Tomcat的Thread Pre Request模型、命令式编程中I/O操作、微服务之间的等待响应延迟。这样的模型难以应对请求压力,容易导致服务丧失即时的响应性,虽然通过限流、熔断、降级、服务隔离等手段可以从架构上提高服务的响应性。但效率低下的问题仍然存在。
- 响应式编程是一种新的编程技术,实现了非阻塞式的客户端 / 服务器交互过程,因此可以用来构建高性能的应用程序。对比命令式编程其优势在于
- 不使用Thread Pre Request模型,少量线程处理大量请求
- 执行I/O操作不再让线程等待
- 简化并行调用
- 支持背压,让客户端告诉服务端他的处理能力。
二、响应式编程思想
响应式编程,是使用异步、事件驱动构建的非阻塞式应用程序。此类应用程序,仅需少量线程即可横向拓展。支持背压技术,防止生产者压垮消费者。
其设计目标
- 响应性(以时序的方式响应)
- 健壮性(发生错误也能保证响应性)
- 弹性(可以在不同的负载下保持响应性)
- 消息驱动(依赖异步消息传递机制)
三、实现响应式编程的探索
实现响应式应用程序基本思想
- 使用异步数据流进行编程,流是一个时序事件序列,可以发布三种不同的事件,值、错误、完成信号
- 基于观察者模式,监听一个流成为订阅,定义的函数是观察者,流是被观察者
探索过程中发现的问题
- 纯拉取模式存在的问题:在早期响应式编程规范未定的时期,所有响应式库的设计思想,都是把数据源从源头推送到订阅者,因为拉取模型会导致数据源存在大量空闲时间,因为其无法预知即将到来的请求数量。并且产生了大量的网络活动,花费大量时间。
- **批量拉取模式存在的问题:**批量拉取,解决了频繁的网络请求带来的损耗,但仍然存在问题,1.数据库批量查询数据时,客户端空闲 2.批量数据的发送更加耗时 3.可能会拉取多余的数据
- 推送模式流量控制问题:如果使用推送模式生产者消费者处理能力不一致,系统的稳定性仍然无法保障,虽然可以使用无界队列、有界丢弃队列、有界阻塞队列等对其两边处理能力差异进行缓和,但仍然会导致系统过度复杂化,并且需要额外工作来找到这几种模式的平衡。后面响应式流规范提出了背压机制来解决了这一难题。但是Rx 1.0中并不存在背压机制。
四、响应式框架历史和现状
历史
- 2011年,微软发布.NET响应式拓展,Reactive Extensions 称为ReactiveX 或者RX,它混合了迭代器模式和**观察者模式。**不同之处在于一个是推送模式,一个是基于迭代器的拉模式。RX的基本思想是,事件是数据,数据是事件。
- 2013年年末,Netflix 的 bench ristensen 和 david karnok在一起制定了响应式流规范Reactive-Streams,官方网址:http://www.reactive-streams.org 规范文档:https:///reactive-streams/reactive-streams-jvm/blob/v1.0.3/README.md
- 2014年11月 RxJava 1.0发布,是java的ReactiveX实现,很大程度由Netflix 的 bench ristensen 和 david karnok这些大佬创建。
现状
JVM领域,构建响应式系统最知名的框架是,Akka和Vert.x的生态。
- Akka 是一个受欢迎的框架,具有大量功能和大型社区。然而,Akka 最初是作为 Scala生态系统的一部分构建的,在很长一段时间内,它仅在基于 Scala 编写的解决方案中展示了它的强大功能。尽管 Scala 是一种基于 JVM 的语言,但它与 Java 明显不同。几年前,Akka 直接开始支持 Java,但出于某些原因,它在 Java 世界中不像在 Scala 世界中那么受欢迎。
- Vert.x 框架也是构建高效响应式系统的强大解决方案。Vert.x 的设计初衷是作为Node.js在 Java 虚拟机上的替代方法,它支持非阻塞和事件驱动。然而,Vert.x 仅在几年前才开始具备竞争力
- 过去这些年Spring在java应用程序框架中一直占有举足轻重的地位,但是很长时间里它在构建健壮的响应式系统方面存在一些局限性。
五、响应式编程规范
响应式编程规范官网:http://www.reactive-streams.org 响应式编程文档:https:///reactive-streams/reactive-streams-jvm/blob/v1.0.3/README.md 规定:
- 规范规定异步组件之间使用背压进行交互
- 响应式规范在Java 9中使用Flow API适配,Flow是互操作的规范,不是具体实现。他的语义和响应式流规范一致。
- 响应式流规范,可以使用纯粹的阻塞等待,也可以采用纯拉取模型(只在onNext方法中请求新元素),同时支持带有背压控制的混合推拉模型,使用时如果使用纯推模型,只需要请求Long.MAX_VALUE个元素即可。
- 响应式流规范中接口
- Publisher接口 表示数据流的生产者,或者数据源。提供一个subscribe方法,供订阅者进行注册
- Subscriber接口 表示消费者,其包含 onSubscribe 、onNext、onError、onComplete等事件的处理方式的定义。
- Subscription接口 表示订阅票据,消费者可以通过该对象联系生产者,消费者在订阅成功的onSubscribe方法中可取得该对象。该对象的request方法用于让订阅者通知发布者随后需要的元素数量,cancel方法让订阅住主动取消订阅
- Processor接口 如果实体需要转换进来的项目,并且传递给后续的订阅者那么他既是发布者又是消费者,便可以实现processor接口。