webFlux&Reactor

  配置springcloud的gateway的时候,需要用到webflux,所以需要学习一下。以下是目前我的理解,可能不正确,但是会持续修正。

  什么是webflux?目前的认知是异步非阻塞IO的webMVC,因为之前的Springmvc是基于同步阻塞IO模型的Servlet实现的,包括tomcat,jetty等传统的servlet容器,因为他们的servlet不支持异步非阻塞,所以,每个请求在获取资源的时候,系统资源都在该请求的名下,显而易见,这是会浪费很多资源的,因为在进行资源IO的时候,如果资源阻塞,线程等资源需要等待被请求资源的IO唤醒。所以传统的tomcat,jetty在性能方面有很大的限制,这也是springmvc面临的问题。

  所以springwebflux伴随spring5出现了,基于servlet3.1支持异步非阻塞IO,也就是说当请求a的资源IO出现阻塞并不会影响b资源的请求。

以及下图sringboot2.0中webflux和mvc技术栈的对比:

  

  可以看出响应式Reactive技术栈是其新的技术要点。

Router Functions: 对应@Controller,@RequestMapping等标准的Spring MVC注解,提供一套函数式风格的API,用于创建Router,Handler和Filter。

Webflux:核心模块,联系Router Functions模块和Reactive Streams模块,提供响应式编程。

Reactive Streams:一种支持背压(Backpressure)机制的异步数据流处理标准,主要实现有RxJava和Reactor,springwebflux采用的是Reactor

响应式编程:

  响应式编程就是基于reactor的思想,当你做一个带有一定延迟的才能够返回的io操作时,不会阻塞,而是立刻返回一个流,并且订阅这个流,当这个流上产生了返回数据,可以立刻得到通知并调用回调函数处理数据。

Backpressure机制:

  生产速度大于消费速度,所以需要 Buffer;

  外部条件有限制,所以 Buffer 需要有上限;

  Buffer 达到上限这个现象,有一个简化的等价词叫做 Backpressure;

  Backpressure 的出现其实是一种危险边界,唯一的选择是丢弃新事件。

Reactor:

  Reactor模式也叫反应器模式,大多数IO组件如reids,netty都在使用的IO模式,以此来解决高性能并发。Reactor被分为handlerreactor两个部分,前者负责业务处理,后者负责io接受分发。

  回顾一下IO历史:

    连轴转:一个while处理全部请求(单线程)。一个请求阻塞全部阻塞。

    connection per thread:一个请求一个线程。一个线程只能处理一个请求,即使语法上允许一个线程处理多个请求,但是一个线程上的一个请求被阻塞,其他也会阻塞;每个线程都是系统的资源,耗费资源巨大,创建销毁线程也需要消耗资源。

    Java.NIO: (NIO的Selector网络通讯就是一个单线程版的Reactor)。一个典型的NIO代码:

 1 static class Server
 2     {
 3
 4         public static void testServer() throws IOException
 5         {
 6
 7             // 1、获取Selector选择器
 8             Selector selector = Selector.open();
 9
10             // 2、获取通道
11             ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
12             // 3.设置为非阻塞
13             serverSocketChannel.configureBlocking(false);
14             // 4、绑定连接
15             serverSocketChannel.bind(new InetSocketAddress(SystemConfig.SOCKET_SERVER_PORT));
16
17             // 5、将通道注册到选择器上,并注册的操作为:“接收”操作
18             serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
19
20             // 6、采用轮询的方式,查询获取“准备就绪”的注册过的操作
21             while (selector.select() > 0)
22             {
23                 // 7、获取当前选择器中所有注册的选择键(“已经准备就绪的操作”)
24                 Iterator<SelectionKey> selectedKeys = selector.selectedKeys().iterator();
25                 while (selectedKeys.hasNext())
26                 {
27                     // 8、获取“准备就绪”的时间
28                     SelectionKey selectedKey = selectedKeys.next();
29
30                     // 9、判断key是具体的什么事件
31                     if (selectedKey.isAcceptable())
32                     {
33                         // 10、若接受的事件是“接收就绪” 操作,就获取客户端连接
34                         SocketChannel socketChannel = serverSocketChannel.accept();
35                         // 11、切换为非阻塞模式
36                         socketChannel.configureBlocking(false);
37                         // 12、将该通道注册到selector选择器上
38                         socketChannel.register(selector, SelectionKey.OP_READ);
39                     }
40                     else if (selectedKey.isReadable())
41                     {
42                         // 13、获取该选择器上的“读就绪”状态的通道
43                         SocketChannel socketChannel = (SocketChannel) selectedKey.channel();
44
45                         // 14、读取数据
46                         ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
47                         int length = 0;
48                         while ((length = socketChannel.read(byteBuffer)) != -1)
49                         {
50                             byteBuffer.flip();
51                             System.out.println(new String(byteBuffer.array(), 0, length));
52                             byteBuffer.clear();
53                         }
54                         socketChannel.close();
55                     }
56
57                     // 15、移除选择键
58                     selectedKeys.remove();
59                 }
60             }
61
62             // 7、关闭连接
63             serverSocketChannel.close();
64         }
65
66         public static void main(String[] args) throws IOException
67         {
68             testServer();
69         }
70     }

从上面代码可知,NIO通过一个线程就完成了传统IO需要大量资源提供的IO操作,且效率极高。但是缺点也很明显,任何IO资源的操作都有可能导致阻塞,进而导致这个NIO系统阻塞。这在web项目中是不能容忍的。所以也就没有单线程的Reactor。

  多线程的Reactor:

    1. Handler资源处理器的执行被放入线程池中进行,以多线程的方式进行资源处理。(主要)

    2. 而对于Reactor而言,可以仍为单个线程。如果服务器为多核的CPU,为充分利用系统资源,可以将Reactor拆分为两个线程。(升级)

Reactor模式的优点:

1)响应快,不必为单个同步时间所阻塞,虽然Reactor本身依然是同步的;

2)编程相对简单,可以最大程度的避免复杂的多线程及同步问题,并且避免了多线程/进程的切换开销;

3)可扩展性,可以方便的通过增加Reactor实例个数来充分利用CPU资源;

4)可复用性,reactor框架本身与具体事件处理逻辑无关,具有很高的复用性; 

参考文章:https://www.jianshu.com/p/4e02c35152a9

https://www.cnblogs.com/yuanrw/p/10050509.html

http://gee.cs.oswego.edu/dl/cpjslides/nio.pdf

https://www.cnblogs.com/crazymakercircle/p/9833847.html

https://www.jianshu.com/p/d187de1d320a

原文地址:https://www.cnblogs.com/YsirSun/p/12547550.html

时间: 2024-10-08 18:53:50

webFlux&Reactor的相关文章

WebFlux系列(九)WebClient Uri列表、数组传参

#Java#Spring#WebFlux#Reactor#WebClient#Uri#传参#数组#列表# WebClient Uri列表.数组传参 视频讲解:  https://www.bilibili.com/video/av83351261/ 服务端: @RestController class EmployeeController { @GetMapping("employee") public Mono<String> requestList(@RequestPar

微服务网关解决方案调研和使用总结 专题

文章转自 http://xujin.org/janus/gw-solution/?from=timeline 一.什么是网关 1.1 什么是网关 API Gateway(APIGW / API 网关),顾名思义,是出现在系统边界上的一个面向API的.串行集中式的强管控服务,这里的边界是企业IT系统的边界,可以理解为企业级应用防火墙,主要起到隔离外部访问与内部系统的作用.在微服务概念的流行之前,API网关就已经诞生了,例如银行.证券等领域常见的前置机系统,它也是解决访问认证.报文转换.访问统计等问

两年摸爬滚打 Spring Boot,总结了这 16 条最佳实践

前言Spring Boot是最流行的用于开发微服务的Java框架.在本文中,我将与你分享自2016年以来我在专业开发中使用Spring Boot所采用的最佳实践.这些内容是基于我的个人经验和一些熟知的Spring Boot专家的文章. 在本文中,我将重点介绍Spring Boot特有的实践(大多数时候,也适用于Spring项目).以下依次列出了最佳实践,排名不分先后. 1.使用自定义BOM来维护第三方依赖 这条实践是我根据实际项目中的经历总结出的. Spring Boot项目本身使用和集成了大量

【华为云技术分享】Spring Boot 最流行的 16 条实践解读!

Spring Boot是最流行的用于开发微服务的Java框架.在本文中,将与大家分享自2016年以来笔者在专业开发中使用Spring Boot所采用的最佳实践.这些内容是基于笔者个人经验和一些熟知的Spring Boot专家的文章. 在本文中,将重点介绍Spring Boot特有的实践(大多数时候,也适用于Spring项目).以下依次列出了最佳实践,排名不分先后. 1.使用自定义BOM来维护第三方依赖 这条实践是我根据实际项目中的经历总结出的. Spring Boot项目本身使用和集成了大量的开

通过Spring Boot Webflux实现Reactor Kafka

在Apache Kafka简介中,我们研究了分布式流媒体平台Apache Kafka.这一次,我们将关注Reactor Kafka,这个库可以创建从Project Reactor到Kafka Topics的Reactive Streams,反之亦然. 我们将使用两个小型示例应用程序,Paymentprocessor Gateway和PaymentValidator.这些应用程序的代码可以在这里找到. Paymentprocessor网关提供了一个小网页,可以生成一个随机的信用卡号码(显然是伪造的

响应式编程库Reactor 3 Reference Guide参考文档中文版(v3.2.0)

Project Reactor 是 Spring WebFlux 的御用响应式编程库,与 Spring 是兄弟项目. 关于如何基于Spring的组件进行响应式应用的开发,欢迎阅读系列文章<响应式Spring的道法术器>. 官方参考文档地址:http://projectreactor.io/docs/core/release/reference/中文翻译文档地址:http://htmlpreview.github.io/?https://github.com/get-set/reactor-co

响应式Spring的道法术器(Spring WebFlux 快速上手 + 全面介绍)

1. Spring WebFlux 2小时快速入门 Spring 5 之使用Spring WebFlux开发响应式应用. lambda与函数式(15min) Reactor 3 响应式编程库(60min) Spring Webflux和Spring Data Reactive开发响应式应用(45min) 通过以上内容相信可以对Spring 5.0 推出的响应式开发有了初步的体会.如果希望有更加深入的了解,欢迎阅读下边的系列文章-- 2. 响应式Spring的道法术器 这个系列的文章是为了记录下自

(14)Reactor调度器与线程模型——响应式Spring的道法术器

本系列文章索引<响应式Spring的道法术器>前情提要 Spring WebFlux快速上手 | Spring WebFlux性能测试前情提要:Reactor 3快速上手 | 响应式流规范 | 自定义数据流本文测试源码 2.4 调度器与线程模型 在1.3.2节简单介绍了不同类型的调度器Scheduler,以及如何使用publishOn和subscribeOn切换不同的线程执行环境. 下边使用一个简单的例子再回忆一下: @Test public void testScheduling() { F

基于Angular和Spring WebFlux做个小Demo

前言 随着Spring Boot2.0正式发布,Spring WebFlux正式来到了Spring Boot大家族里面.由于Spring WebFlux可以通过更少的线程去实现更高的并发和使用更少的硬件资源去实现扩展,我对此很感兴趣.同时Angular6也发布了,也想试试自己Angular的功底,便基于Angular和Spring WebFlux做个一个简单礼品管理系统的demo.至于angular和spring boot的集成可以参考该博客Angular和Spring Boot一起做个项目 响