读Java实战(第二版)笔记17_反应式编程

1. 再次出现在聚光灯下的原因

1.1. 基本思想已经有二三十年的历史

1.2. 大数据

1.2.1. 以PB计量的大数据

1.2.2. 当前互联网中流量最大的部分是移动流量

1.2.3. 物联网(Internet of things, IoT)流量取代移动流量成为互联网流量的主流,这种情况还会进一步加剧

1.3. 异构环境

1.3.1. 移动设备

1.3.2. 运行着数千个多核处理器的云端集群

1.4. 使用模式

1.4.1. 用户期望毫秒级的响应时间

1.4.2. 希望应用百分之百时时刻刻都在线

2. 反应式编程

2.1. 一种利用反应式流的编程技术

2.1.1. 以异步方式处理潜在无边界数据流的标准技术

2.2. 以异步的方式处理、整合来自不同系统和源头的数据流

2.2.1. 比线程更轻量级

2.2.2. 提升了创建并发以及异步应用的抽象层次

2.2.3. 任务能以异步的方式运行

2.3. 可以构建单一组件或者应用

2.4. 协调多个组件,将它们搭建成一个反应式系统

2.5. 主线程池中运行的线程执行的都为无阻塞的操作

2.5.1. 确保所有的CPU核都能得到最充分的利用

2.6. 不要在主事件循环中添加可能阻塞的操作

2.6.1. 所有I/O密集型的操作

2.6.1.1. 访问数据库或文件系统

2.6.1.2. 调用远程服务

2.6.2. 无法预测何时能够结束

2.6.3. 可能消耗比较长时间的事件

2.7. 开辟独立的线程池用于执行阻塞式操作

2.7.1. 为CPU密集型和I/O密集型的操作分别创建单独的线程池

2.7.2. 更精细地监控不同类型任务的性能

2.7.3. 更好地配置和调整线程池的规模

2.7.4. 更好地适应业务的需求

2.8. 背压

2.8.1. 发表-订阅模式下的一种常见的流量控制机制

2.8.2. 提供了一种协议,可以在不阻塞线程的情况下,避免数据接收方被压垮

2.8.3. 避免流中事件处理的消费者由于处理速度较慢,被一个或多个快速的生产者压垮

2.8.4. 组件需要一种方式来向上游生产者反馈,让它们减缓生产速度

2.8.5. 告诉生产者它在接收更多数据之前,在给定的时间内能够接受和处理多少事件

3. Flow类

3.1. java.util.concurrent.Flow

3.1.1. Java 9

3.2. 所有实现该接口的库需要遵守的合约

3.2.1. 使构建于不同的反应式库之上的应用间能相互协调、相互理解沟通的通用语言

3.2.2. 接口可以帮助你更好地构建你的程序思维

3.2.3. 并不能帮你更快地完成程序设计

3.3. 标准化使得不同库之间互通和调用成为可能

3.3.1. Akka

3.3.2. RxJava

3.4. 发布-订阅”模型

3.4.1. 发布者(Publisher)

3.4.1.1. 顺序事件的提供者

3.4.1.2. 事件的数量可能没有上限

3.4.1.3. 受背压机制的制约

3.4.1.4. 按照Subscriber的反馈进行元素的生产

3.4.1.5. Java函数式接口

3.4.2. 订阅者(Subscriber)

3.4.2.1. 把自己注册为该事件的监听方从而完成对Publisher事件的注册

3.4.3. 订阅(Subscription)

3.4.3.1. 流量控制,包括Publisher与Subscriber之间的背压都是由Subscription管理的

3.4.3.2. cancel()方法的实现必须是幂等和线程安全的

3.4.3.2.1. 调用它一次与重复调用多次的效果是同样的
3.4.3.2.2. 任何对Subscription的额外调用都不会有副作用

3.4.4. 处理者(Processor)

3.4.4.1. 反应式流中事件的转化阶段

3.4.4.2. 转换数据

3.4.5. 所有方法都返回void,从而确保它们能以完全异步的方式实现

4. RxJava

4.1. 应用最广泛的反应式库

4.1.1. 诞生于Netflix

4.1.2. 对微软.Net环境中反应式扩展(reactive extension, Rx)项目的迁移

4.1.3. 比Java 9的Flow API更方便

4.1.3.1. 更加丰富的函数集

4.1.3.2. 更灵活地对流进行整合、创建以及过滤操作

4.2. io.reactivex.Observable

4.2.1. 不支持背压

4.2.2. 适用于

4.2.2.1. 用户接口事件(譬如鼠标移动)

4.2.2.2. 流元素不超过一千个

4.2.2.3. 基于图形用户界面的事件流

4.2.2.4. 无法背压或不常发生的事件时

4.2.3. onSubscribe方法需要一个Disposable参数

4.2.4. 只在需要Observable的额外结构时使用Observable,否则就应该继续使用它的Publisher接口

4.3. Subscriber可以通过request(Long.MAX_VALUE)调用关闭背压功能

4.4. just()工厂方法

4.4.1. 将一个或多个元素转换为Observable

4.5. interval工厂方法

4.5.1. 按照固定的时间间隔发出事件

4.6. blockingSubscribe方法

4.6.1. 调用当前线程(在这个例子中就是main函数所在的线程)的回调函数

4.7. 弹珠图

5. 反应式宣言

5.1. 2013年至2014年间发起

5.2. 开发反应式应用和系统的规范

5.3. Jonas Bonér、Dave Farley、Roland Kuhn和Martin Thompson

5.4. 响应性

5.4.1. 反应式系统的响应时间很快

5.4.2. 响应时间应该是稳定且可预测的

5.4.2.1. 用户才能明确地设定他的预期

5.4.2.2. 增强用户的信心

5.5. 韧性

5.5.1. 系统在出现失败时依然能继续响应服务

5.5.1.1. 组件运行时复制

5.5.1.2. 从时间(发送方和接受方都拥有相互独立的生命周期)和空间(发送方和接收方运行于不同的进程)维度对组件进行解耦

5.5.1.3. 任何一个组件都能以异步的方式向其他组件分发任务

5.6. 弹性

5.6.1. 应用的工作负载

5.6.2. 有能力自动地适配和服务更大的负荷

5.7. 消息驱动

5.7.1. 组件间的松耦合

5.7.2. 组件隔离

5.7.3. 位置透明性

5.7.3.1. 实现韧性的决定性要素

5.7.3.2. 使得系统能够依据当前的负荷情况,对应用进行复制或者自动地水平扩展

5.7.3.3. 位置无关的扩展也是反应式应用(异步、并发、即时松耦合)与反应式系统(凭借位置透明性从空间角度解耦)之间的另一个区别

6. 反应式应用

6.1. 主要对临时数据流进行处理

6.2. 事件驱动型

6.2.1. 事件会被所有注册了该事件的组件接收

6.3. 异步、并发、即时松耦合

7. 反应式系统

7.1. 多个独立应用可以像一个单一系统那样步调一致地工作,同时其又具备良好的扩展性

7.2. 各个应用也是充分解耦的

7.2.1. 即使其中某一个应用发生失效,也不会拖垮整个系统

7.3. 用于构造应用以及协调组件间的通信

7.3.1. 以异步的方式发送和接收的,这种方式有效地解耦了发送方与接收方

7.4. 消息驱动系统

7.4.1. 消息往往是直接发送给某个单一目标的

7.5. 组件间完全的解耦合既是实现有效隔离的必要前提,也是保障系统在遭遇失效(韧性)和超大负荷(弹性)时仍能保持响应的基础

7.6. 韧性更偏向于容错

7.6.1. 系统不只要能优雅地降级,更重要的是能通过隔离失效组件,将系统重新拉回健康状

7.6.2. 失效节点的管理可以不受失效组件自身的影响,在一个安全的上下文中进行

7.7. 凭借位置透明性从空间角度解耦

7.7.1. 反应式系统的所有组件都可以和其他任何服务通信,无须顾忌接收方在什么位置

posted @ 2023-02-22 08:16  躺柒  阅读(81)  评论(0编辑  收藏  举报