百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 编程网 > 正文

反应式编程之Spring Web-Flux/Project Reactor

yuyutoo 2025-01-14 18:41 10 浏览 0 评论

介绍

反应式编程代表了我们对应用程序执行模型的看法的改变。在响应式应用程序中,执行不遵循一个请求由一个线程处理的线性模型,而是以事件驱动和非阻塞的方式处理多个请求。

反应式编程提供了一种基于事件的异步流式编程模型,可以处理来自单个或多个客户端的大量并发请求。反应式应用程序通常需要少量线程来垂直扩展,而不是水平扩展。使用响应式编程设计和实现应用程序使应用程序能够最大限度地利用 CPU,从而使应用程序比传统的 Java Web 应用程序具有更高的性能和效率。

反应式编程的特点:

1.异步

2.非阻塞

3. 事件驱动的数据处理方法(事件驱动架构)

术语“反应式”是指围绕对变化做出反应而构建的编程模型,例如对 I/O 事件做出反应的网络组件、对鼠标事件做出反应的 UI 控制器等。从这个意义上说,非阻塞是反应性的,因为我们现在不是被阻塞,而是在操作完成或数据可用时对通知做出反应。(将看到如何发生这种情况的示例)

反应式编程的实现

1. 反应式流(Reactive Streams)

2. RxJava 2.0(最初由Netflix开发,后来开源)

3. Project Reactor(本文)

4.Vert.x

5.其他


Project Reactor的特点:

1. I/O 操作的异步和非阻塞

2. 背压

3.错误处理

4. 处理来自单个或多个客户端的大量并发请求。

5.函数式编程

6. 反应式流是基于推送的,从而提高了性能

7.简单易用的 API (用于 [0|1] 元素) 和(用于 [N] 元素)

I/O 调用非阻塞

反应式和非阻塞式的主要预期好处是能够使用少量固定数量的线程和更少的内存进行扩展。

阻塞可能是浪费,总的来说,有两种方法可以提高程序的性能:

1.并行化以使用更多线程和更多硬件资源。

2.在如何使用当前资源方面寻求更高的效率。

如果仔细观察,一旦程序涉及一些延迟(特别是 I/O,例如数据库请求或网络调用),就会浪费资源,因为线程(可能很多线程)现在处于空闲状态,等待数据。


阻塞请求处理(每个连接一个线程)

非阻塞异步请求处理(事件回调)


事件处理是通过使用:Channel、Buffer 和 Selector 来实现的。

下面列出了一些常用的Channel:

  • FileChannel → 通过文件读写
  • SocketChannel → 通过 TCP 套接字读写
  • ServerSocketChannel →监听客户端的 TCP 连接,为每个 TCP 连接创建新的 SocketChannel
  • DatagramChannel →通过UDP协议读写


Buffer可以看成是一个数据容器,可以用数组来实现。无论是从通道读取还是写入通道,都必须先将数据放入缓冲区。

线程选择器通道

Selector是 Java NIO 中的核心类,它监视和处理在多个注册的 Channel 中发生的感兴趣的 IO 事件。通过这种机制,我们可以只用一个线程来维护多个连接。只有当这些连接之间真正发生了 IO 事件时,才会真正调用 IO 流程逻辑。每次有新连接进来时,不需要启动一个新线程,因此可以显着降低系统负载。

与 Selector 一起,SelectionKey 是另一个重要的类,它代表一个到达的事件。这两个类构成了 NIO 服务器的关键逻辑。

上图显示了在单个线程上运行的 Selector 对多个通道(或连接)的监控。


背压

背压就是下游比上游处理的慢时的一种反馈信号。

Reactive Streams 中的背压概念既优雅又强大。它将允许在响应式应用程序中使用缓慢的消费者,而不会“阻塞”太多信息。可以缓冲未处理的数据。

当消费者在生产者上订阅自己时,它将获得一个订阅。这将启用从数据流的消费者到其生产者的反馈机制。通过它,消费者可以指示他能够处理多少数据事件。

当 Consumer 发出可以处理 5 个数据事件的信号时,Producer 将使用 onNext 方法最多调用 Consumer 5 次。消费完这 5 个事件后,Consumer 会向 Producer 请求额外的事件,直到发生 onComplete 或 onError 调用。


简单易用的 API - Mono(用于 [0|1] 元素)和 Flux(用于 [N] 元素)

Spring WebFlux 围绕 2 个 API 的 Flux 和 Mono 展开 ……

Flux,一个 0-N 项的异步序列

下图显示了如何Flux转换过程:

Mono,异步 0-1 结果

下图显示了如何Mono转换过程:


代码示例:

非反应性代码

@GetMapping("/tweets-blocking")
public List<Tweet> getTweetsBlocking() {
  log.info("Starting BLOCKING Controller!”);
  final String uri = getSlowServiceUri();
  ResponseEntity<List<Tweet>> response = new RestTemplate().exchange(uri, HttpMethod.GET, null, new ParameterizedTypeReference<List<Tweet>>(){});
  List<Tweet> result = response.getBody();
  result.forEach(tweet -> log.info(tweet.toString()));
  log.info("Exiting BLOCKING Controller!");
  return result;
}


反应式代码

@GetMapping(value = "/tweets-non-blocking")
public Flux<Tweet> getTweetsNonBlocking() {
    log.info("Starting NON-BLOCKING Controller!");
    WebClient.create()
        .get()
        .uri(getSlowServiceUri())
        .retrieve()
        .bodyToFlux(Tweet.class)
        .subscribe(tweet -> log.info(tweet.toString()));
    log.info("Exiting NON-BLOCKING Controller!");
    return tweetFlux;
}

两者不同的一点是:反应式中直到订阅的时候(subscribes)才会处理,即延迟执行/懒式执行。

总结

Spring Boot 反应式(Spring Webflux)与非反应式堆栈的比较


有什么优点和缺点?

优点

  • 代码更简洁,更简洁
  • 更容易阅读(一旦你掌握了它)
  • 更容易扩展(管道任何操作)
  • 更好的错误处理
  • 事件驱动的启发 -> 与流(Kafka、RabbitMQ 等)配合得很好
  • 背压(客户端可以控制流量)
  • 非阻塞 I/O 操作(这意味着更好的响应时间)

缺点

· 大部分时间存储数据流需要更多内存(因为它是基于一段时间的流)

  • 一开始可能会觉得学习非常规(需要一切都是流)

· 与传统java风格相比不同的编程风格

· 一切都必须围绕 Mono/Flux

什么时候使用?

实现高吞吐量

系统中的大量数据流

什么时候不使用

当系统内没有太多数据需要处理时

什么是反应式系统?

反应式系统与反应式编程不同。反应式编程用于代码级别,而反应式系统处理架构。

·响应能力:对用户可用,并且无论发生什么(过载、故障等),都准备好响应他们。

·弹性:保持不受故障、中断和极高负载的影响。

·弹性:有效利用资源并平衡机器性能——垂直扩展或缩减——或轻松调节涉及的机器数量——水平扩展或缩减——取决于负载。

·消息驱动特性:通过向可寻址的接收者发送不可变消息来实现完全无阻塞的通信。

官网:https://projectreactor.io/docs/core/release/reference/#getting-started-introducing-reactor

相关推荐

当 Linux 根分区 (/) 已满时如何释放空间?

根分区(/)是Linux文件系统的核心,包含操作系统核心文件、配置文件、日志文件、缓存和用户数据等。当根分区满载时,系统可能出现无法写入新文件、应用程序崩溃甚至无法启动的情况。常见原因包括:...

玩转 Linux 之:磁盘分区、挂载知多少?

今天来聊聊linux下磁盘分区、挂载的问题,篇幅所限,不会聊的太底层,纯当科普!!1、Linux分区简介1.1主分区vs扩展分区硬盘分区表中最多能存储四个分区,但我们实际使用时一般只分为两...

Linux 文件搜索神器 find 实战详解,建议收藏

在Linux系统使用中,作为一个管理员,我希望能查找系统中所有的大小超过200M文件,查看近7天系统中哪些文件被修改过,找出所有子目录中的可执行文件,这些任务需求...

Linux 操作系统磁盘操作(linux 磁盘命令)

一、文档介绍本文档描述Linux操作系统下多种场景下的磁盘操作情况。二、名词解释...

Win10新版19603推送:一键清理磁盘空间、首次集成Linux文件管理器

继上周四的Build19592后,微软今晨面向快速通道的Insider会员推送Windows10新预览版,操作系统版本号Build19603。除了一些常规修复,本次更新还带了不少新功能,一起来了...

Android 16允许Linux终端使用手机全部存储空间

IT之家4月20日消息,谷歌Pixel手机正朝着成为强大便携式计算设备的目标迈进。2025年3月的更新中,Linux终端应用的推出为这一转变奠定了重要基础。该应用允许兼容的安卓设备...

Linux 系统管理大容量磁盘(2TB+)操作指南

对于容量超过2TB的磁盘,传统MBR分区表的32位寻址机制存在限制(最大支持2.2TB)。需采用GPT(GUIDPartitionTable)分区方案,其支持64位寻址,理论上限为9.4ZB(9....

Linux 服务器上查看磁盘类型的方法

方法1:使用lsblk命令lsblk输出说明:TYPE列显示设备类型,如disk(物理磁盘)、part(分区)、rom(只读存储)等。...

ESXI7虚机上的Ubuntu Linux 22.04 LVM空间扩容操作记录

本人在实际的使用中经常遇到Vmware上安装的Linux虚机的LVM扩容情况,最终实现lv的扩容,大多数情况因为虚机都是有备用或者可停机的情况,一般情况下通过添加一块物理盘再加入vg,然后扩容lv来实...

5.4K Star很容易!Windows读取Linux磁盘格式工具

[开源日记],分享10k+Star的优质开源项目...

Linux 文件系统监控:用脚本自动化磁盘空间管理

在Linux系统中,文件系统监控是一项非常重要的任务,它可以帮助我们及时发现磁盘空间不足的问题,避免因磁盘满而导致的系统服务不可用。通过编写脚本自动化磁盘空间管理,我们可以更加高效地处理这一问题。下面...

Linux磁盘管理LVM实战(linux实验磁盘管理)

LVM(逻辑卷管理器,LogicalVolumeManager)是一种在Linux系统中用于灵活管理磁盘空间的技术,通过将物理磁盘抽象为逻辑卷,实现动态调整存储容量、跨磁盘扩展等功能。本章节...

Linux查看文件大小:`ls`和`du`为何结果不同?一文讲透原理!

Linux查看文件大小:ls和du为何结果不同?一文讲透原理!在Linux运维中,查看文件大小是日常高频操作。但你是否遇到过以下困惑?...

使用 df 命令检查服务器磁盘满了,但用 du 命令发现实际小于磁盘容量

在Linux系统中,管理员或开发者经常会遇到一个令人困惑的问题:使用...

Linux磁盘爆满紧急救援指南:5步清理释放50GB+小白也能轻松搞定

“服务器卡死?网站崩溃?当Linux系统弹出‘Nospaceleft’的红色警报,别慌!本文手把手教你从‘删库到跑路’进阶为‘磁盘清理大师’,5个关键步骤+30条救命命令,快速释放磁盘空间,拯救你...

取消回复欢迎 发表评论: