想让系统更具有弹性?了解背压机制和响应式流的秘密!

简介: 想让系统更具有弹性?了解背压机制和响应式流的秘密!

分析传统开发模式和响应式编程实现方法之间的差别引出了数据流的概念

1 引言

从“流”的概念出发,并引入响应式流程规范,从而分析响应式编程中所包含的各个核心组件。

2 流的概念

由生产者生产,并由一或多个消费者消费的元素序列。这种生产者/消费者模型也称发布/订阅模型。


Reactive Streams 是 2013 年底由 Netflix、Lightbend 和 Pivotal 的工程师发起的一项计划,旨在为无阻塞异步流处理提供一个标准。解决处理元素流的问题——如何将元素流从发布者传递到订阅者,而不需要发布者阻塞,或订阅者有无限制的缓冲区或丢弃。

3 流的处理模型

拉模式

消费者主动从生产者拉取元素。

推模式

生产者将元素推送给消费者

4 流量控制

4.1 v(生产者生产数据) < v(消费者消费数据)

消费者消费数据没有任何压力,也就不需要进行流量的控制。

4.2 v(生产者生产数据) > v(消费者消费数据)

消费者可能因为无法处理过多的数据而发生崩溃。

一般就是在生产者与消费者之间加一个队列做缓冲。我们知道队列具有存储与转发的功能,所以可以用它来进行一定的流量控制。

5 队列选型

无界队列

  • 优势:确保消费者消费到所有的数据
  • 劣势:系统的回弹性降低,任何一个系统不可能拥有无限的资源,一旦内存等资源耗尽,系统就可能会有崩溃的风险。

有界丢弃队列

有界丢弃队列考虑了资源的限制,适用于允许丢消息的业务场景。但消息重要性很高的场景显然不可能采取这种队列。

有界阻塞队列

6 背压(Backpressure)机制

纯“推”模式下的数据流量会有很多不可控制的因素,需要在“推”模式和“拉”模式之间考虑一定的平衡性,从而优雅地实现流量控制

下游能够向上游反馈流量请求的机制。

如果消费者消费数据的速度赶不上生产者生产数据的速度,它就会持续消耗系统的资源。使得消费者可以根据自身当前的处理能力通知生产者来调整生产数据的速度,这就是背压。

7 响应式流规范

针对流量控制的解决方案以及背压机制都包含在响应式流规范中,其中包含了响应式编程的各个核心组件。

8 响应式流的核心接口

8.1 Publisher

一种可以生产无限数据的发布者。

public interface Publisher<T> {
    /**
     * 请求 Publisher 开始流式传输数据。
     * 这是一个“工厂方法”,可以多次调用,每次开始一个新的 Subscription.
     * 每个 Subscription 只能为一个 Subscriber.
     * A Subscriber 只能订阅一次 Publisher
     * 如果 拒绝 Publisher 订阅尝试或失败,它将通过 发出 Subscriber.onError(Throwable)错误信号
     */
    public void subscribe(Subscriber<? super T> s);
}

Publisher 里的 subscribe 方法传入 Subscriber 接口,这里用的是回调,Publisher 根据收到的请求向当前订阅者 Subscriber 发送元素。


,发出信号的元素类型。

8.2 Subscriber

可以从发布者那里订阅并接收元素的订阅者。

public interface Subscriber<T> {
    public void onSubscribe(Subscription s);
    public void onNext(T t);
    public void onError(Throwable t);
    public void onComplete();
}

Subscriber 接口定义的这组方法构成了数据流请求和处理的基本流程,其中,onSubscribe() 从命名上看就是一个回调方法,当发布者的 subscribe() 方法被调用时就会触发这个回调。而在该方法中有一个参数 Subscription,可以把这个 Subscription 看作是一种用于订阅的上下文对象。Subscription 对象中包含了这次回调中订阅者想要向发布者请求的数据个数。


当订阅关系已经建立,那么发布者就可以调用订阅者的 onNext() 方法向订阅者发送一个数据。这个过程是持续不断的,直到所发送的数据已经达到 Subscription 对象中所请求的数据个数。这时候 onComplete() 方法就会被触发,代表这个数据流已经全部发送结束。而一旦在这个过程中出现了异常,那么就会触发 onError() 方法,我们可以通过这个方法捕获到具体的异常信息进行处理,而数据流也就自动终止了。

8.3 Subscription

确保生产者、消费者针对数据处理速度达成一种动态平衡的基础,流量控制中实现背压的关键。

public interface Subscription {
    public void request(long n);
    public void cancel();
}

响应式流规范非常灵活,还可提供独立的“推”模型和“拉”模型。

响应式流是一种规范,而该规范的核心价值,就在于为业界提供了一种非阻塞式背压的异步流处理标准。

业界主流响应式开发库包括:

  • RxJava
  • Akka
  • Vert.X
  • Project Reactor

总结

本文分析了数据流的概念的分类以及“推”流模式下的流量控制问题,从而引出了响应式系统中的背压机制。

响应式流规范是对响应式编程思想精髓的呈现

对于开发人员而言,理解这一规范有助于更好的掌握开发库的使用方法和基本原理。

FAQ

简要描述响应式流规范中数据的生产者和消费者之间的交互关系。


响应式流规范中,数据的生产者和消费者之间的交互关系是基于观察者模式实现的。生产者通过创建一个可观察的数据流并向消费者提供订阅方法,消费者可以通过订阅这个数据流来获取数据。一旦生产者有新的数据产生,它会将数据发送给所有已订阅该数据流的消费者。消费者可以通过取消订阅方法来停止接收数据。这种交互关系使得生产者和消费者之间解耦,同时也允许消费者按需获取数据,从而实现了高效的异步编程。


目录
相关文章
|
2月前
|
边缘计算 JSON 物联网
解锁业务灵活性:RuleGo规则引擎的高效解耦与实时响应秘籍
RuleGo是一个基于Go语言的轻量级、高性能规则引擎,旨在通过动态规则链和组件化设计,简化复杂系统的业务逻辑管理和实时响应。
解锁业务灵活性:RuleGo规则引擎的高效解耦与实时响应秘籍
|
25天前
|
存储 缓存 数据安全/隐私保护
说一说你对移动应用中的离线模式的实现。
【4月更文挑战第2天】移动应用的离线模式允许用户在无网情况下仍能部分使用应用,依赖于数据缓存和本地存储。应用在联网时缓存关键数据,离线时从本地读取。数据同步通过延迟策略在重连时完成,敏感信息加密存储并定期备份。开发者还需关注用户体验、性能优化及错误处理,确保离线模式的无缝衔接和稳定性。
15 1
|
1月前
|
消息中间件 存储 监控
【ZeroMQ的SUB视角】深入探讨订阅者模式、C++编程实践与底层机制
【ZeroMQ的SUB视角】深入探讨订阅者模式、C++编程实践与底层机制
116 1
|
7月前
|
存储 Java 数据处理
响应式流的核心机制——背压机制
响应式流的核心机制——背压机制
|
移动开发 网络协议 前端开发
webim 实现实时通讯的 4 种方式
webim 实现实时通讯的 4 种方式
webim 实现实时通讯的 4 种方式
【鸿蒙】订阅分布式数据变化
客户端需要实现KvStoreObserver接口。 构造并注册KvStoreObserver实例。
【鸿蒙】订阅分布式数据变化
|
编解码 光互联
关于云流化系统-实时云渲染延时性的讨论
时云渲染系统来做程序的流化,是将程序放在服务器上,用户终端的各种操作指令完成都是借助的服务器算力。而为了用户能拥有和本地安装类似的体验效果,指令执行和传回终端的时间就必须尽可能短,这是实时云渲染系统很重要的一个参数:延迟性。没有延迟,该方案就无法落地
191 0
关于云流化系统-实时云渲染延时性的讨论
|
存储 缓存 前端开发
OpenIM重大优化-消息按需加载 一致性缓存 uniapp发布
OpenIM重大优化-消息按需加载 一致性缓存 uniapp发布
240 0
OpenIM重大优化-消息按需加载 一致性缓存 uniapp发布
EMQ
|
存储 SQL 缓存
eKuiper Newsletter 2022-06|离线缓存重发机制升级,优化弱网场景使用
六月,项目圆满完成了在基金会的第一次年度 review,并确立了下一年度升级到 Stage 2 的目标。
EMQ
113 0
|
Java 容器 Spring
基于事件流的轻量级异常容错设计—支持接口可重入
## 写在前面 在我们平时的业务代码中,最常见的代码结构就是外部的请求打过来,首先进行必要的参数校验,接着根据参数对关联实体的状态进行校验,然后再校验业务逻辑,最后推进关联实体的状态。下面以一段代码简单示例一下 ```java pulic class ReentryServiceImpl implements ReentryService { publi