响应式编程总览-异步编程范式

In computing, reactive programming is an asynchronous programming paradigm concerned with data streams and the propagation of change. - Reactive programming - Wikipediareact

在上述响应式编程(如下简称RP)的定义中,除了异步编程,还包含两个重要的关键词:spring

  • Data streams: 即数据流,分为静态数据流(好比数组,文件)和动态数据流(好比事件流,日志流)两种。基于数据流模型,RP得以提供一套统一的Stream风格的数据处理接口。和Java 8中的Stream API相比,RP API除了支持静态数据流,还支持动态数据流,而且容许复用和同时接入多个订阅者。
  • The propagation of change: 变化传播,简单来讲就是以一个数据流为输入,通过一连串操做转化为另外一个数据流,而后分发给各个订阅者的过程。这就有点像函数式编程中的组合函数,将多个函数串联起来,把一组输入数据转化为格式迥异的输出数据。

一个容易混淆的概念是响应式设计,虽然它的名字中也包含了“响应式”三个字,但其实和RP彻底是两码事。响应式设计是指网页可以自动调整布局和样式以适配不一样尺寸的屏幕,属于网站设计的范畴,而RP是一种关注系统可响应性,面向数据流的编程思想或者说编程框架。编程

特性

从本质上说,RP是一种异步编程框架,和其余框架相比,RP至少包含了如下三个特性:数组

  • 描述而非执行:在你最终调用subscribe()方法以前,从发布端到订阅端,没有任何事会发生。就比如不管多长的水管,只要水龙头不打开,水管里的水就不会流动。为了提升描述能力,RP提供了比Stream丰富的多的多的API,好比buffer()merge()onErrorMap()等。
  • 提升吞吐量: 相似于HTTP/2中的链接复用,RP经过线程复用来提升吞吐量。在传统的Servlet容器中,每来一个请求就会发起一个线程进行处理。受限于机器硬件资源,单台服务器所能支撑的线程数是存在一个上限的,假设为T,那么应用同时能处理的请求数(吞吐量)必然也不会超过T。但对于一个使用Spring 5开发的RP应用,若是运行在像Netty这样的异步容器中,不管有多少个请求,用于处理请求的线程数是相对固定的,所以最大吞吐量就有可能超过T。
  • 背压(Backpressure)支持:简单来讲,背压就是一种反馈机制。在通常的Push模型中,发布者既不知道也不关心订阅者的处理速度,当数据的发布速度超过处理速度时,须要订阅者本身决定是缓存仍是丢弃。若是使用RP,决定权就交回给发布者,订阅者只须要根据本身的处理能力问发布者请求相应数量的数据。你可能会问这不就是Pull模型吗?实际上是不一样的。在Pull模型中,订阅者每次处理完数据,都要从新发起一次请求拉取新的数据,而使用背压,订阅者只须要发起一次请求,就能接二连三的重复请求数据。

适用场景

了解了RP的这些特性,你可能已经猜测到RP有哪些适用场景了。通常来讲,RP适用于高并发、带延迟操做的场景,好比如下这些状况(的组合):缓存

  • 一次请求涉及屡次外部服务调用
  • 非可靠的网络传输
  • 高并发下的消息处理
  • 弹性计算网络

代价

Every coin has two sides.服务器

和任何框架同样,有优点必然就有劣势。RP的两个比较大的问题是:网络

  • 虽然复用线程有助于提升吞吐量,但一旦在某个回调函数中线程被卡住,那么这个线程上全部的请求都会被阻塞,最严重的状况,整个应用会被拖垮。
  • 难以调试。因为RP强大的描述能力,在一个典型的RP应用中,大部分代码都是以链式表达式的形式出现,好比flux.map(String::toUpperCase).doOnNext(s -> LOG.info("UC String {}", s)).next().subscribe(),一旦出错,你将很难定位到具体是哪一个环节出了问题。所幸的是,RP框架通常都会提供一些工具方法来辅助进行调试。

http://emacoo.cn/backend/reactive-overview/并发

相关文章
相关标签/搜索