接上一篇:实战SpringCloud响应式微服务系列教程(第一章)

1.1.2背压

背压是响应式编程的核心概念,这一节也是我们了解响应式编程的重点。

1.背压的机制

在生产者/消费者模型中,我们意识到消费者在消费由生产者生产的数据的同时,也需要有一种能够向上游反馈流量需求的机制,这种能够向上游反馈请求的机制称之为背压。

如下图所示

现在我们从一个具体的角度来说背压的概念。在1.1.1中我们了解了同步消费和异步消费,其中异步消费者会向生产者订阅消费数据,当有新的数据可用时,消费者会通过之前订阅时提供的回调函数激活调用过程。

如果生产者发出的数据比消费者能够处理的数据量大而且快时,消费者可能会被迫一直再获取或处理数据,消耗越来越多的资源,从而埋下潜在的风险。为了防止这一点,需要有一种机制,消费者可以通知生产者降低生产数据的速度。生产者可以通过多种方式来实现这一要求,这时候我们就会用到背压机制。

采用背压机制后,消费者告诉生产者降低生产数据速度并保存元素,知道消费者能够处理更多的元素。使用背压可以有效地避免过快的生产者压制消费者。如果生产者要一直生产和保存元素,使用背压也可能会要求其拥有无限制的缓冲区。生产者也可以实现有界缓冲区来保存有限数量的元素,如果缓冲区已满可以选择放弃。

2.背压的实现方式

背压的实现方式有两种,一种是阻塞式背压另一种是非阻塞式背压。

1、阻塞式背压

阻塞式背压是比较容易实现的,例如:当生产者和消费者在同一个线程中运行时,其中任何一方都将阻塞其他线程的执行。这就意味着,当消费者被执行时,生产者就不能发出任何新的数据元素。因而也需要一中自然地方式来平衡生产数据和消费数据的过程。

在有些情况下,阻塞式背压会出现不良的问题,比如:当生产者有多个消费者时,不是所有消费者都能以同样的速度消费消息。当消费者和生产者在不同环境中运行时,这就达不到降压的目的了。

2、非阻塞式背压

背压机制应该以非阻塞式的方式工作,实现非阻塞式背压的方法是放弃推策略,采用拉策略。生产者发送消息给消费者等操作都可以保存在拉策略当中,消费者会要求生产者生成多少消息量,而且最多只能发送这些量,然后等到更多消息的请求。(关于推策略和拉策略请回顾1.1.1中的流的概念

1.1.3 响应式流

响应式编程的另外一个核心概念就是响应式流。响应式流是一种规范,这种规范表现在技术上就是一批被预先定义好的接口。

1.响应式流规范

响应式流规范是提供非阻塞背压的异步流处理标准倡议的。响应式流的目标是定义将数据流从生产者传递到消费者而不需要生产者阻塞。在响应式流模型中,消费者向生产者发送多个元素的异步请求,然后生产者向消费者发送合适数量的数据。

各个响应式开发库都要遵循响应式流规范,采用规范的好处是显而易见的。由于各个响应式都遵循一套规范,因而互相兼容,不同的开发库之间也是可以进行交流的。甚至可以在同一个项目中使用多个开发库。而Spring WebFlux响应式web是采用Reactor框架来实现的。(其他开发库可百度了解这里我们只探讨reactor)。

虽然响应式流规范用来约束响应式开发库的实现方式的,但是作为使用者而言,能够了解这一规范,对我们了解使用开发库的方法和基本原理很有帮助,因为规范内容都是对响应式编程思想的精髓呈现。

2.响应式流接口

Java API响应式流有4个接口,即Publisher<T>SubscriptionSubscriber<T>Processor<T,R>

1、Publisher<T>

发布者(Publisher)是潜在的包含无限数量的有序元素的生产者,他根据收到的请求向当前订阅者发送元素。接口定义如下:

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

2、Subscriber<T>

订阅者从发布这那里订阅并且接收元素。发布者想订阅者发送订阅令牌。使用订阅令牌,订阅者向发布者请求多个元素。当元素准备就绪时,发布者就会向订阅者发送合适数量的元素。然后订阅者可以请求更多的元素,发布者也可能有多个来自订阅者的待处理请求。接口定义如下:

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

当执行发布者的subscribe()方法时,发布者会回调订阅者的onSubscribe()方法。在这个方法中订阅者通常会借助传入的Subscription 对象向发布者请求n个数据。然后发布者通过不断调用onNext()方法想订阅者发出最多n个数据。如果数据全部发送完毕,就会调用onComplete()方法告知订阅者所需要的n个数据已经发送完毕。如果有错误发生就会通过调用onError()方法发出错误数据,这同样也会终止数据流。

3、Subscription

订阅(Subscription )表示订阅者订阅的一个发布者的令牌,当订阅请求成功时,发布者将其传递给订阅者,订阅者使用订阅令牌与发布者进行交互,比如:请求更多的元素或取消订阅。接口定义如下:

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

当发布者调用subscribe()方法注册订阅者时,会通过订阅者的回调方法onSubscribe()传入Subscription对象,之后订阅者就可以使用Subscription对象的request()方法向发布者请求数据了。

Publisher<T>SubscriptionSubscriber<T>三者的交互如下:

4、Processor<T,R>

处理器(Processor)充当订阅者和发布者之间的处理媒介,Processor接口继承了PublisherSubscribe接口,它用于转换发布者/订阅者管道中的元素。

Processor<T,R>订阅类型T的数据元素,接收并转换为R的数据,然后发布该数据。处理器在发布者/订阅者管道中充当转换器的角色。接口定义如下:

public interface Processor<T,R> extends Subscriber<T>,Publisher<R>{

}

ProcessorSubscriberPublisher于一身,三者之间的关系如下所示:

这四个接口是实现各个响应式开发库之间互相兼容的桥梁,响应式流规范也仅仅聚焦于此,而对于转换、合并、分组等操作并未做要求。也是一个非常抽象且精简的接口规范。

实战SpringCloud响应式微服务系列教程(第二章)的更多相关文章

  1. 实战SpringCloud响应式微服务系列教程(第九章)使用Spring WebFlux构建响应式RESTful服务

    本文为实战SpringCloud响应式微服务系列教程第九章,讲解使用Spring WebFlux构建响应式RESTful服务.建议没有之前基础的童鞋,先看之前的章节,章节目录放在文末. 从本节开始我们 ...

  2. 实战SpringCloud响应式微服务系列教程(第三章)

    接着之前的: 实战SpringCloud响应式微服务系列教程(第一章) 实战SpringCloud响应式微服务系列教程(第二章) 1.1.3Reactor框架 响应式编程是一种编程模型,本节将介绍这种 ...

  3. 实战SpringCloud响应式微服务系列教程(第四章)

    接上一篇: 实战SpringCloud响应式微服务系列教程(第一章) 实战SpringCloud响应式微服务系列教程(第二章) 实战SpringCloud响应式微服务系列教程(第三章) 1.1.4 引 ...

  4. 实战SpringCloud响应式微服务系列教程(第六章)

    本章节介绍:Flux和Mono操作符 和其他主流的响应式编程一样,Reactor框架的设计目标也是为了简化相应式流的使用方法.为此Reactor框架提供了大量操作符用于操作Flux和Mono对象. 本 ...

  5. 实战SpringCloud响应式微服务系列教程(第七章)

    本章节继续介绍:Flux和Mono操作符(二) 1.条件操作符 Reactor中常用的条件操作符有defaultIfRmpty.skipUntil.skipWhile.takeUntil和takeWh ...

  6. 实战SpringCloud响应式微服务系列教程(第八章)构建响应式RESTful服务

    本文为实战SpringCloud响应式微服务系列教程第八章,讲解构建响应式RESTful服务.建议没有之前基础的童鞋,先看之前的章节,章节目录放在文末. 1.使用springboot2.1.4构建RE ...

  7. 实战SpringCloud响应式微服务系列教程(第十章)响应式RESTful服务完整代码示例

    本文为实战SpringCloud响应式微服务系列教程第十章,本章给出响应式RESTful服务完整代码示例.建议没有之前基础的童鞋,先看之前的章节,章节目录放在文末. 1.搭建响应式RESTful服务. ...

  8. 实战SpringCloud响应式微服务系列教程(第一章)

    前言 在当今互联网飞速发展的时代,业务需求不断的更新和产品的迭代给系统开发过程和编程模式也带来巨大挑战,Spring Cloud微服务也随之应用而生,从springboot1.x到springboot ...

  9. Cobalt Strike系列教程第二章:Beacon详解

    上周更新了Cobalt Strike系列教程第一章:简介与安装,文章发布后,深受大家的喜爱,遂将该系列教程的其他章节与大家分享,提升更多实用技能! 第二章:Beacon详解 一.Beacon命令 大家 ...

随机推荐

  1. Hexo+NexT(五):Hexo第三方插件提供功能及配置

    本篇文章介绍NexT中通过第三方实现的功能,有的需要通过额外的插件,有的需要通过第三方提供的功能.这些功能丰富了网站内容,弥补了原生静态网站的不足. Hexo博客专题索引页 增加百度统计分析功能 访问 ...

  2. ASP.NET Core中GetService()和GetRequiredService()之间的区别

    上篇文章<在.NET Core 3.0中的WPF中使用IOC图文教程>中,我们尝试在WPF中应用.NET Core内置的IOC进行编程,在解析MainWindow的时候我用了GetRequ ...

  3. MySQL解决存入数据库和取出数据库时间格式问题

    我们在往数据库里存数据时,时间格式正是我们想要的,然而取数据时去出现了这种情况 这明显不是我们想要的! 解决办法: 在我们配置mysql时添加一行代码: timezone:"08:00&qu ...

  4. idea初见问题整理_错误: -source 1.5 中不支持 diamond 运算符

    最近在移动工程到idea下,顺便改目录结构,遇到的问题不一定全部记录,有些答案摘抄自别人博客,已注明来源,由于不是摘抄自同一作者,且有自己的一些内容,所以标注为原创. 1.(错误: -source 1 ...

  5. ES5_03_Object扩展

    ES5给Object扩展了一些静态方法, 常用的2个: 1. Object.create(prototype, [descriptors]) * 作用: 以指定对象为原型创建新的对象 * 为新的对象指 ...

  6. Java多线程(五):死锁

    死锁 概念 当线程Thread-0持有锁Lock1,Thread-1持有锁Lock2,此时Thread-0申请Lock2锁的使用权,Thread-1申请Lock1锁的使用权,Thread-0和Thre ...

  7. MYSQL事务之Yii2.0商户提现

    我是一个半路出家的PHP程序员,到目前为止,不算在培训班学习的时间,已经写代码整整两年了.可能由于工作业务的原因,在这两年中我没有用到过MySQL事务.就在昨天有个关于支付宝转账的业务不得不使用MyS ...

  8. 一文看懂Python的面向对象编程

    之前在网络上看了很多关于面向对象的编程详解,还是不够过瘾,所以决定自己动手写一篇. 面向对象:Object Oriented Programming,简称OOP,即面向对象程序设计. 类(Class) ...

  9. re正则

    #转义字符和原生字符 import re # # # 转义 # text = 'apple price is $299' # ret = re.search('\$\d+',text) # print ...

  10. 宏旺半导体深度剖析嵌入式存储芯片eMMC原理 一篇概括大全

    eMMC 一直是嵌入式存储市场最主流的选择,除了读写速度快.性价比高外,在节省空间方面也是相当优秀,今天宏旺半导体就和大家详细聊聊eMMC. eMMC 是 embedded MultiMediaCar ...