响应式编程学习
关于响应式编程
响应式编程是一种关注于数据流(datastreams)和变化传递(propagation of change)的异步编程方式。可以用既有的编程语言表达静态(如数组)或动态(如事件源)的数据流。
响应式编程通常作为面向对象编程中的“观察者模式”(Observer design pattern)的一种扩展。
Reactive Streams 与 Iterator Design Pattern 关系
- Iterator:
- 基于Pull模式(拉取),Iterable角色 提供访问元素的方法,但是什么时候执行next()获取元素取决于开发者。
- 命令式编程,详细的命令机器怎么(How)去处理数据以达到你想要的结果(What)。
- Reactive:
- 基于Push模式(推送),Publisher(发布者)-Subscriber(订阅者)角色提供获取元素的方法。当有新的值到来的时候,Publisher通知Subscriber。
- 声明式编程,开发者通过描述“控制流程”来定义对数据流的处理逻辑。
特性
- 变化传递(propagation of change) 类似于Excel的公式计算,一个单元格变化之后,导致直接和间接引用它的其他单元格均发生相应变化。
- 数据流(data stream) 数据/事件在响应式编程里会以数据流的形式发出。
- 声明式(declarative) 声明好了对于数据流“将会”进行什么样的处理,当有数据流过来时,就会按照声明好的处理流程逐个进行处理。(形成了一种计算逻辑对数据的“绑定”。)
- 响应式流(Reactive Stream) 异步非阻塞(Java Stream是同步的),可以通过背压(Backpressure)进行流量控制。
阻塞与异步
- 阻塞式(blocking)编码造成浪费资源,当一个程序面临延迟(通常是I/O方面, 比如数据库读写请求或网络调用),所在线程需要进入 idle 状态等待数据,从而浪费资源。
- 异步非阻塞编码, (任务发起异步调用后)执行过程会切换到另一个 使用同样底层资源 的活跃任务,然后等异步调用返回结果再去处理,避免资源浪费。
- Java的异步
-
Callback:类似于观察者模式,异步方法没有返回值,而是采用一个 callback 作为参数,当结果出来后回调这个 callback。
-
Futures:异步方法 立即 返回一个
Future<T>
,该异步方法要返回结果的是 T 类型,线程实际处理结束时可以拿到结果。 -
缺陷:容易写出回调地狱(Callback Hell)
-
响应式库目标
- 可编排性(Composability)以及可读性(Readability)使用丰富的操作符 来处理形如流的数据
- 在订阅(subscribe)之前什么都不会发生
- 背压(backpressure)具体来说即消费者能够反向告知生产者生产内容的速度的能力
- 高层次 (同时也是有高价值的)的抽象,从而达到 并发无关 的效果
- JVM 异步方式缺陷
关于响应式宣言
响应式宣言是一组架构与设计原则,即时响应性(Responsive)、回弹性(Resilient)、弹性(Elastic)以及消息驱动(Message Driven)。 对于这样的系统,我们称之为响应式系统(Reactive System)。
- 回弹性
- 系统在出现失败时依然保持即时响应性。 失败的扩散被遏制在了每个组件内部,与其他组件相互隔离, 从而确保系统某部分的失败不会危及整个系统,并能独立恢复。每个组件的恢复都被委托给了另一个(外部的)组件。
[如熔断器组件]
- 系统在出现失败时依然保持即时响应性。 失败的扩散被遏制在了每个组件内部,与其他组件相互隔离, 从而确保系统某部分的失败不会危及整个系统,并能独立恢复。每个组件的恢复都被委托给了另一个(外部的)组件。
- 弹性
- 系统在不断变化的工作负载之下依然保持即时响应性。响应式系统可以对输入(负载)的速率变化做出反应,比如通过增加或者减少被分配用于服务这些输入(负载)的资源。
[如DevOps,云原生...]
- 系统在不断变化的工作负载之下依然保持即时响应性。响应式系统可以对输入(负载)的速率变化做出反应,比如通过增加或者减少被分配用于服务这些输入(负载)的资源。
- 消息驱动
- 响应式系统依赖异步的消息传递,从而确保了松耦合、隔离、位置透明的组件之间有着明确边界。
响应式编程与响应式系统
响应式宣言是一组设计原则,一种关于分布式环境下系统架构与设计的思考方式,关注于通过分布式系统的通信和协作所得到的弹性和可靠性(消息驱动),响应式系统是符合这一架构风格的系统。
响应式编程是异步编程下的一个子集,是一种范式,有具体的开发库,侧重于由信息/数据流而不是命令式的控制流来推动逻辑的前进,专注于短时间的数据流链条上的计算(事件驱动)。
一个拥有长期存活的可寻址long-lived addressable组件的消息驱动系统跟一个事件驱动的数据流驱动模型的不同在于,消息具有固定的导向,而事件则没有。消息会有明确的(一个)去向,而事件则只是一段等着被观察observe的信息。
异步且非阻塞执行下的数据流管理——通常只在单个结点或服务中。当有多个结点时,就需要开始认真地考虑像数据一致性data consistency、跨结点沟通cross-node communication、协调coordination、版本控制versioning、编制orchestration、错误管理failure management、关注与责任concerns and responsibilities分离等等的东西——也即是:系统架构。