响应式编程_02基本概念:背压机制 Backpressure

文章目录

  • Pre
    • 流的处理模型
      • 拉模式
      • 推模式
    • 流量控制
      • 产者生产数据的速率小于消费者的场景
      • 生产者生产数据的速率大于消费者消费数据
        • 无界队列
        • 有界丢弃队列
        • 有界阻塞队列
  • 背压机制
  • 响应式流规范
    • 响应式流的核心接口
      • Publisher
      • Subscriber
      • Subscription
    • 响应式流的技术生态圈
  • 小结

在这里插入图片描述


Pre

响应式编程_01基本概念:前世今生通过分析传统开发模式和响应式编程实现方法之间的差别,引出了数据流的概念。我们知道响应式系统都是通过对数据流中每个事件进行处理,来提高系统的即时响应性的。

接下来就先从“流”的概念出发,并引入响应式流程规范,从而分析响应式编程中所包含的各个核心组件,从而可以掌握通过背压机制对流量进行高效控制的系统方法,并基于响应式流规范来实现背压机制。


简单来讲,所谓的流就是由生产者生产并由一个或多个消费者消费的元素序列。这种生产者/消费者模型也可以被称为发布者/订阅者模型。

关于流的介绍,首先明确流的分类,然后再来讨论如何进行流量控制,流量控制是讨论数据流的核心话题

流的处理模型

拉模式

一种就是传统开发模式下的“拉”模式,即消费者主动从生产者拉取元素
在这里插入图片描述

  • 同步阻塞:消费者在拉取数据时需等待生产者返回结果,期间线程可能被阻塞。

  • 主动请求:消费者控制数据获取时机,生产者被动响应。


推模式

另一种就是“推”模式,在这种模式下,生产者将元素推送给消费者。相较于“拉”模式,“推”模式下的数据处理的资源利用率更好,下图所示的就是一种典型的推模式处理流

在这里插入图片描述

上图中,数据流的生产者会持续地生成数据并推送给消费者。这里就引出了流量控制问题,即如果数据的生产者和消费者处理数据的速度是不一致的,我们应该如何确保系统的稳定性呢?


流量控制

产者生产数据的速率小于消费者的场景

先来看第一种场景,即生产者生产数据的速率小于消费者的场景。在这种情况下,因为消费者消费数据没有任何压力,也就不需要进行流量的控制

生产者生产数据的速率大于消费者消费数据

这种情况比较复杂,因为消费者可能因为无法处理过多的数据而发生崩溃。

针对这种情况的一种常见解决方案是在生产者和消费者之间添加一种类似于消息队列的机制。我们知道队列具有存储并转发的功能,所以可以由它来进行一定的流量控制,效果如下图所示.

添加队列机制之后的生产者/消费者场景示意图

在这里插入图片描述


现在,问题的关键就转变为如何设计一种合适的队列。通常,我们可以选择三种不同类型的队列来分别支持不同的功能特性

无界队列

第一种最容易想到的队列就是无界队列(Unbounded Queue),这种队列原则上拥有无限大小的容量,可以存放所有生产者所生产的消息,如下图所示。

在这里插入图片描述

显然,无界队列的优势就是确保了所有消息都能得到消费,但显然会降低系统的回弹性,因为没有一个系统拥有无限的资源。一旦内存等资源被耗尽,系统可能就崩溃了。


有界丢弃队列

与无界队列相对的,更合适的方案是选择一种有界队列。为了避免内存溢出,我们可以使用这样一个队列,一般队列的容量满了,就忽略后续传入的消息,如下图所示。

在这里插入图片描述

上图中,可以看出这个有界队列的容量为 6,所以第 7 和第 8 个元素被丢弃了。然后当消费者消费了一部分消息之后,队列出现了新的空闲位置,后续的消息就又被填充到队列中。当然,这里可以设置一些丢弃元素的策略,比方说按照优先级或先进先出等。

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


有界阻塞队列

如果需要确保消息不丢失,则需要引入有界阻塞队列。在这种队列中,我们会在队列消息数量达到上限后阻塞生产者,而不是直接丢弃消息,如下图所示。

在这里插入图片描述

上图中,队列的容量同样是 6,所以当第 7 个元素到来时,发现队列已经满了,那么生产者就会一直等到队列空间的释放而产生阻塞行为。显然,这种阻塞行为是不可能实现异步操作的,所以,无论从回弹性、弹性还是即时响应性出发,有界阻塞队列都不是我们想要的解决方案。


背压机制

纯“推”模式下的数据流量会有很多不可控制的因素,并不能直接应用,而是需要在“推”模式和“拉”模式之间考虑一定的平衡性,从而优雅地实现流量控制。这就需要引出响应式系统中非常重要的一个概念——背压机制(Backpressure)

什么是背压?简单来说就是下游能够向上游反馈流量请求的机制。通过前面的分析,我们知道如果消费者消费数据的速度赶不上生产者生产数据的速度时,它就会持续消耗系统的资源,直到这些资源被消耗殆尽。

这个时候,就需要有一种机制使得消费者可以根据自身当前的处理能力通知生产者来调整生产数据的速度,这种机制就是背压。采用背压机制,消费者会根据自身的处理能力来请求数据,而生产者也会根据消费者的能力来生产数据,从而在两者之间达成一种动态的平衡,确保系统的即时响应性。


响应式流规范

关于流量控制我们已经讨论了很多,而针对流量控制的解决方案以及背压机制都包含在响应式流规范中,其中包含了响应式编程的各个核心组件,让我们一起来看一下。


响应式流的核心接口

在 Java 的世界中,响应式流规范只定义了四个核心接口,即 Publisher<T>、Subscriber<T>、Subscription 和 Processor<T,R>

Publisher

publisher 代表的就是一种可以生产无限数据的发布者,该接口定义如下所示。

public interface Publisher<T> {public void subscribe(Subscriber<? super T> s);
}

可以看到,Publisher 根据收到的请求向当前订阅者 Subscriber 发送元素。


Subscriber

对应的,Subscriber 代表的是一种可以从发布者那里订阅并接收元素的订阅者。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() 方法,我们可以通过这个方法捕获到具体的异常信息进行处理,而数据流也就自动终止了。


Subscription

Subscription 代表的就是一种订阅上下文对象,它在订阅者和发布者之间进行传输,从而在两者之间形成一种契约关系。Subscription 接口定义如下所示。

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

这里的

  • request() 方法用于请求 n 个元素,订阅者可以通过不断调用该方法来向发布者请求数据;
  • cancel() 方法显然是用来取消这次订阅。

Subscription 对象是确保生产者和消费者针对数据处理速度达成一种动态平衡的基础,也是流量控制中实现背压机制的关键所在,我们可以通过下图来进一步理解整个数据请求和处理过程

Subscription 与背压机制示意图

在这里插入图片描述

Publisher、Subscriber 和 Subscription 接口是响应式编程的核心组件,响应式流规范也只包含了这些接口,因此是一个非常抽象且精简的接口规范。结合前面的讨论结果,我们可以明确,响应式流规范实际上提供了一种“推-拉”结合的混合数据流模型

当然,响应式流规范非常灵活,还可以提供独立的“推”模型和“拉”模型。如果为了实现纯“推”模型,我们可以考虑一次请求足够多的元素;而对于纯“拉”模型,相当于就是在每次调用 Subscriber 的 onNext() 方法时只请求一个新元素


响应式流的技术生态圈

响应式流是一种规范,而该规范的核心价值就在于为业界提供了一种非阻塞式背压的异步流处理标准。各个供应商都可以基于该规范实现自己的响应式开发库,而这些开发库之间则可以做到互相兼容、相互交互。

目前,业界主流响应式开发库包括

  • RxJava、
  • Akka、
  • Vert.x
  • Project Reactor

小结

我们进一步分析了数据流的概念的分类,以及“推”流模式下的流量控制问题,从而引出了响应式系统中的背压机制。而流量控制的解决方案都包含在响应式流规范中,我们对这一规范中的核心组件展开了详细的说明。

响应式流规范是对响应式编程思想精髓的呈现,对于开发人员而言,理解这一规范有助于更好地掌握开发库的使用方法和基本原理

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/70229.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Android 进程间通信

什么是IPC&#xff1f; Android 进程间通信&#xff08;IPC&#xff0c;Inter-Process Communication&#xff09;是Android操作系统中不同进程间交换数据和资源的一种机制。由于Android是多任务操作系统&#xff0c;每个应用通常运行在自己的进程中&#xff0c;以提高安全性和…

Macos给brew安装的neo4j配置apoc插件

文章目录 打开并查看neo4j版本下载apoc插件安装apoc插件修改conf配置文件验证成果 打开并查看neo4j版本 open /usr/local/Cellar/neo4j下载apoc插件 apoc插件下载界面&#xff0c;选择与neo4j兼容的apoc版本apoc与neo4j版本对应表 安装apoc插件 将下载的apoc jar包&#…

回顾生化之父三上真司的游戏思想

1. 放养式野蛮成长路线&#xff0c;开创生存恐怖类型 三上进入capcom后&#xff0c;没有培训&#xff0c;没有师傅手把手的指导&#xff0c;而是每天摸索写策划书&#xff0c;老员工给出不行的评语后&#xff0c;扔掉旧的重写新的。 然后突然就成为游戏总监&#xff0c;进入开…

Go语言的转义字符

文章目录 1. Go语言的转义字符(escapechar)2. 小结和提示 1. Go语言的转义字符(escapechar) 说明:常用的转义字符有如下: \t : 表示一个制表符&#xff0c;通常使用它可以排版\n &#xff1a;换行符\\ &#xff1a;一个\\" &#xff1a;一个"\r &#xff1a;一个回…

Django框架丨从零开始的Django入门学习

Django 是一个用于构建 Web 应用程序的高级 Python Web 框架&#xff0c;Django是一个高度模块化的框架&#xff0c;使用 Django&#xff0c;只要很少的代码&#xff0c;Python 的程序开发人员就可以轻松地完成一个正式网站所需要的大部分内容&#xff0c;并进一步开发出全功能…

《Kettle保姆级教学-核心概念解析》

目录 一、什么是ETL&#xff1f;1、ETL 的三个主要阶段2、ETL 的应用场景3、ETL 工具 二、什么是Kettle&#xff1f;1、Kettle 的核心功能2、Kettle 的主要组件3、Kettle 的优点4、Kettle 的应用场景 三、Kettle核心概念1. 转换&#xff08;Transformation&#xff09;2. 作业&…

DeepSeek:全栈开发者视角下的AI革命者

目录​​​​​​​ DeepSeek&#xff1a;全栈开发者视角下的AI革命者 写在前面 一、DeepSeek的诞生与定位 二、DeepSeek技术架构的颠覆性突破 1、解构算力霸权&#xff1a;从MoE架构到内存革命 2、多模态扩展的技术纵深 3、算法范式的升维重构 4、重构AI竞争规则 三、…

Linux设备树(DTS)入门学习

前言&#xff1a; Linux设备树(DTS)入门学习&#xff0c;资料搜集。从零开始入门学习Linux设备树 Device Tree (DTS)&#xff0c;建议的学习流程如下&#xff1a; 1. 讯为电子在哔站上的-Linux设备树视频教程&#xff08;嵌入式学习之Linux驱动&#xff08;第七期_设备树_全新…

用python实现进度条

前言 在Python中&#xff0c;可以使用多种方式实现进度条。以下是几种常见的进度条格式的实现方法&#xff1a; 1. 使用 tqdm 库 tqdm 是一个非常流行的库&#xff0c;可以轻松地在循环中显示进度条。 from tqdm import tqdm import time# 示例&#xff1a;简单的进度条 fo…

Java 大视界 -- 深度洞察 Java 大数据安全多方计算的前沿趋势与应用革新(52)

&#x1f496;&#x1f496;&#x1f496;亲爱的朋友们&#xff0c;热烈欢迎你们来到 青云交的博客&#xff01;能与你们在此邂逅&#xff0c;我满心欢喜&#xff0c;深感无比荣幸。在这个瞬息万变的时代&#xff0c;我们每个人都在苦苦追寻一处能让心灵安然栖息的港湾。而 我的…

【蓝桥杯嵌入式】LED

1、电路图 74HC573是八位锁存器&#xff0c;当控制端LE脚为高电平时&#xff0c;芯片“导通”&#xff0c;LE为低电平时芯片“截止”即将输出状态“锁存”&#xff0c;led此时不会改变状态&#xff0c;所以可通过led对应的八个引脚的电平来控制led的状态&#xff0c;原理图分析…

苹果再度砍掉AR眼镜项目?AR真的是伪风口吗?

曾经&#xff0c;AR游戏一度异常火热&#xff0c;宝可梦go让多少人不惜翻墙都要去玩&#xff0c;但是也没过去几年&#xff0c;苹果被曝出再度砍掉了AR眼镜项目&#xff0c;面对着市场的变化&#xff0c;让人不禁想问AR真的是伪风口吗&#xff1f; 一、苹果再度砍掉AR眼镜项目&…

PostgreSQL 数据库备份与还原

为了安全与数据共享等&#xff0c;创建好的数据库有时候需要备份操作和还原操作。数据库的备份与还原主要是三个命令&#xff1a;pg_dump、pg_dumpall 和 pg_restore 。 其中pg_dump用于备份单个数据库&#xff0c;它支持多种备份格式&#xff08;SQL、自定义等&#xff09;&a…

排序算法--计数排序

唯一种没有比较的排序(指没有前后比较,还是有交换的)。统计每个元素出现的次数&#xff0c;直接计算元素在有序序列中的位置&#xff0c;要求数据是整数且范围有限。适用于数据为小范围整数&#xff08;如年龄、成绩&#xff09;&#xff0c;数据重复率较高时效率更优。可用于小…

C#结合html2canvas生成切割图片并导出到PDF

目录 需求 开发运行环境 实现 生成HTML范例片断 HTML元素转BASE64 BASE64转图片 切割长图片 生成PDF文件 小结 需求 html2canvas 是一个 JavaScript 库&#xff0c;它可以把任意一个网页中的元素&#xff08;包括整个网页&#xff09;绘制到指定的 canvas 中&#xf…

java进阶专栏的学习指南

学习指南 java类和对象java内部类和常用类javaIO流 java类和对象 类和对象 java内部类和常用类 java内部类精讲Object类包装类的认识String类、BigDecimal类初探Date类、Calendar类、SimpleDateFormat类的认识java Random类、File类、System类初识 javaIO流 java IO流【…

RK3566-移植5.10内核Ubuntu22.04

说明 记录了本人使用泰山派&#xff08;RK3566&#xff09;作为平台并且成功移植5.10.160版本kernel和ubuntu22.04&#xff0c;并且成功配置&连接网络的完整过程。 本文章所用ubuntu下载地址&#xff1a;ubuntu-cdimage-ubuntu-base-releases-22.04-release安装包下载_开源…

stm32点灯 GPIO的输出模式

目录 1.选择RCC时钟 2.SYS 选择调试模式 SW 3.GPIO 配置 4.时钟树配置&#xff08; 默认不变&#xff09;HSI 高速内部时钟8Mhz 5.项目配置 6.代码 延时1s循环LED亮灭 1.选择RCC时钟 2.SYS 选择调试模式 SW 3.GPIO 配置 4.时钟树配置&#xff08; 默认不变&#xff09…

Docker基础以及单体实战

Docker 一、Docker1.1 Docker组成1.2 Dcoker运行图1.3 名称空间Namepace 1.4 docker、Docker compose、kubermetes 二、Docker安装2.1 在线Docker安装2.2 使用官方通用安装脚本2.3 二进制安装Docker三、Docker基础命令3.1 启动类3.2 镜像类3.3 容器类3.4 网络类3.5 Docker comp…

备考蓝桥杯嵌入式7——ADC电压采集

目录 ADC电压采集 代码书写 ADC电压采集 ADC的含义就是将一个范围内的电压映射成为数字传入进来。举个例子&#xff0c;当我们想要做一个非常简单的电压测量计的时候&#xff0c;使用ADC就会将我们的模拟电压信号转化为数字电压信号。 我们的板子上有两个电压采集旋钮&#…