SpringCloud Gateway及相关概念简介

2022年9月4日11:13:37

SpringCloud Gateway 简介

参考文档:SpringCloud gateway

1. 定义

SpringCloud Gateway 作为 Spring Cloud 生态系统中的网关,目标是替代 Zuul,在Spring Cloud 2.0以上版本中,没有对新版本的Zuul 2.0以上最新高性能版本进行集成,仍然还是使用的Zuul 2.0之前的非Reactor模式的老版本。而为了提升网关的性能,SpringCloud Gateway是基于WebFlux框架实现的,而WebFlux框架底层则使用了高性能的Reactor模式通信框架Netty。

Webflux模式替换了旧的Servlet线程模型。用少量的线程处理request和response io操作,这些线程称为Loop线程,而业务交给响应式编程框架处理,响应式编程是非常灵活的,用户可以将业务中阻塞的操作提交到响应式框架的work线程中执行,而不阻塞的操作依然可以在Loop线程中进行处理,大大提高了Loop线程的利用率。

Spring Cloud Gateway 的目标,不仅提供统一的路由方式,并且基于 Filter 链的方式提供了网关基本的功能,例如:安全,监控/指标,和限流。主要特征如下:

  • 基于 Spring Framework 5,Project Reactor 和 Spring Boot 2.0
  • 集成 Hystrix 断路器
  • 集成 Spring Cloud DiscoveryClient
  • Predicates 和 Filters 作用于特定路由,易于编写的 Predicates 和 Filters
  • 具备一些网关的高级功能:动态路由、限流、路径重写

2. 处理流程

客户端向 Spring Cloud Gateway 发出请求。然后在 Gateway Handler Mapping 中找到与请求相匹配的路由,将其发送到 Gateway Web Handler。Handler 再通过指定的过滤器链来将请求发送到我们实际的服务执行业务逻辑,然后返回。

Spring Cloud Gateway  -> Gateway Handler Mapping  -> Gateway Web Handler -> filter(pre或者post)  -> 目标请求

3. 路由

模块 内容
Route(路由) 路由是网关的基本单元,由ID、URI、一组Predicate、一组Filter组成,根据Predicate进行匹配转发。
Predicate(谓语、断言) 路由转发的判断条件,目前SpringCloud Gateway支持多种方式,常见如:Path、Query、Method、Header等,写法必须遵循 key=vlue的形式
Filter(过滤器) 过滤器是路由转发请求时所经过的过滤逻辑,可用于修改请求、响应内容

SpringCloud Gateway及相关概念简介

4. 熔断降级

在分布式系统中,网关作为流量的入口,因此会有大量的请求进入网关,向其他服务发起调用,其他服务不可避免的会出现调用失败(超时、异常),失败时不能让请求堆积在网关上,需要快速失败并返回给客户端,想要实现这个要求,就必须在网关上做熔断、降级操作。

如果请求发生故障的时候,这个请求会一直堆积在网关上,网关上堆积多了就会给网关乃至整个服务都造成巨大的压力,甚至整个服务宕掉。因此要对一些服务和页面进行有策略的降级,以此缓解服务器资源的的压力,以保证核心业务的正常运行,同时也保持了客户和大部分客户的得到正确的相应,所以需要网关上请求失败需要快速返回给客户端。

当上游的请求,进入了Hystrix熔断降级机制时,就会调用fallbackUri配置的降级地址。需要注意的是,还需要单独设置Hystrix的commandKey的超时时间

思考:如何判断是否需要进行熔断?

个人理解:当有请求失败的时候,会直接返回预定义好的回复内容:包括两种,一种是失败的错误消息,一种是默认的数据(这种与真实的业务数据有格式相同,但是内容是固定的),目的只是为了快速响应请求,避免请求堆积网关。

5. 高级配置

  • 分布式限流

    从某种意义上讲,令牌桶算法是对漏桶算法的一种改进,桶算法能够限制请求调用的速率,而令牌桶算法能够在限制调用的平均速率的同时还允许一定程度的突发调用。在令牌桶算法中,存在一个桶,用来存放固定数量的令牌。算法中存在一种机制,以一定的速率往桶中放令牌。每次请求调用需要先获取令牌,只有拿到令牌,才有机会继续执行,否则选择选择等待可用的令牌、或者直接拒绝。放令牌这个动作是持续不断的进行,如果桶中令牌数达到上限,就丢弃令牌,所以就存在这种情况,桶中一直有大量的可用令牌,这时进来的请求就可以直接拿到令牌执行,比如设置qps为100,那么限流器初始化完成一秒后,桶中就已经有100个令牌了,这时服务还没完全启动好,等启动完成对外提供服务时,该限流器可以抵挡瞬时的100个请求。所以,只有桶中没有令牌时,请求才会进行等待,最后相当于以一定的速率执行。

    在Spring Cloud Gateway中,有Filter过滤器,因此可以在“pre”类型的Filter中自行实现上述三种过滤器。但是限流作为网关最基本的功能,Spring Cloud Gateway官方就提供了RequestRateLimiterGatewayFilterFactory这个类,适用在Redis内的通过执行Lua脚本实现了令牌桶的方式。

    在定义限流时,需要设置用于限流的键的解析器的 Bean 对象的名字。它使用 SpEL 表达式根据#{@beanName}从 Spring 容器中获取 Bean 对象。Bean对象可以通过设置uri、username、userId等作为限流条件

    问题: 针对不同用户,实现不同的限流措施?

  • 健康检查配置

    admin-client、actuator健康检查配置,为之后的功能提供支持

  • 统一配置跨域请求

    现在的请求通过经过gateWay网关时,需要在网关统一配置跨域请求,需求所有请求通过

  • 整合Sentinel完成流控和降级

    使用Sentinel作为gateWay的限流、降级、系统保护工具,由于sentinel的工作原理其实借助于全局的filter进行请求拦截并计算出是否进行限流、熔断等操作的

spring cloud gateway 与spring cloud 、nacos结合的部署架构,spring cloud gateway作为微服务单独进行部署


补充说明:

java NIO

NIO(Non-blocking I/O,在Java领域,也称为New I/O),是一种同步非阻塞的I/O模型,也是I/O多路复用的基础,已经被越来越多地应用到大型应用服务器,成为解决高并发与大量连接、I/O处理问题的有效方式。

参考文档:Java NIO浅析

IO的实现逻辑大体是什么样子的

NIO的读写函数可以立刻返回,这就给了我们不开线程利用CPU的最好机会:如果一个连接不能读写(socket.read()返回0或者socket.write()返回0),我们可以把这件事记下来。因此只需要一个线程不断地轮询这些事件,一旦有就绪的时间,处理即可。不需要多线程。

NIO由原来的阻塞读写(占用线程)变成了单线程轮询事件,找到可以进行读写的网络描述符进行读写。除了事件的轮询是阻塞的(没有可干的事情必须要阻塞),剩余的I/O操作都是纯CPU操作,没有必要开启多线程。

NIO给我们带来了些什么

  • 事件驱动模型
  • 避免多线程
  • 单线程处理多任务
  • 非阻塞I/O,I/O读写不再阻塞,而是返回0
  • 基于block的传输,通常比基于流的传输更高效
  • 更高级的IO函数,zero-copy
  • IO多路复用大大提高了Java网络应用的可伸缩性和实用性

响应式编程

参考文档:响应式编程Flux 和 Mono 、reactor实战 (史上最全)

定义

Reactive Programming

响应式编程(Reactive Programming) ,这是微软为了应对 高并发环境下 的服务端编程,提出的一个实现 异步编程 的方案。响应式编程就是基于reactor的思想,当你做一个带有一定延迟的才能够返回的io操作时,不会阻塞,而是立刻返回一个流,并且订阅这个流,当这个流上产生了返回数据,可以立刻得到通知并调用回调函数处理数据。

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

响应式传播核心特点之一:变化传播:一个单元格变化之后,会像多米诺骨牌一样,导致直接和间接引用它的其他单元格均发生相应变化。

Reactive Stream

响应式流(Reactive Stream) 就是反应式编程相关的规范,在 Java 平台上,由Netflix(开发了 RxJava)、TypeSafe(开发了 Scala、Akka)、Pivatol(开发了 Spring、Reactor)共同制定。

它由以下几个组件组成:

发布者:发布元素到订阅者
订阅者:消费元素
订阅:在发布者中,订阅被创建时,将与订阅者共享
处理器:发布者与订阅者之间处理数据

Reactor

Reactor 是一个运行在 Java8 之上满足 Reactice 规范的响应式框架,它提供了一组响应式风格的 API。

Reactor 框架是 Pivotal 基于 Reactive Programming 思想实现的。它符合 Reactive Streams 规范。它提供了Mono和Flux API 类型,两个核心类:Flux<T>Mono<T>,两个核心类都实现 Publisher 接口,通过一组与 ReactiveX 运算符词汇表一致的丰富运算符来处理 0…1 () 和 0…N ()的数据序列。是一个用于 JVM 的完全非阻塞的响应式编程框架,具备高效的需求管理,可以很好的处理 “backpressure”。 Reactor 就是 Spring WebFlux 的首选 反应式库。在上面的概念中,大家最重要是要记住FluxMono这两个Reactor` 的核心类:

  • Mono:实现发布者 Publisher,并返回 0 或 1 个元素,最多只触发一个事件,所以可以把 Mono 用于在异步任务完成时发出通知。
  • Flux:实现发布者 Publisher,并返回 N 个元素,它可以触发零到多个事件,并根据实际情况结束处理或触发错误。

Flux 和 Mono 都是数据流的发布者,使用 Flux 和 Mono 都可以发出三种数据信号:元素值,错误信号,完成信号;错误信号和完成信号都代表终止信号,终止信号用于告诉订阅者数据流结束了,错误信号终止数据流同时把错误信息传递给订阅者。

Flux

Reactor中的发布者(Publisher)由FluxMono两个类定义,它们都提供了丰富的操作符(operator)。一个Flux对象代表一个包含0…N个元素的响应式序列,元素可以是普通对象、数据库查询的结果、http响应体,甚至是异常。而一个Mono对象代表一个包含零/一个(0…1)元素的结果。

//创建一个流,并直接往流上发布一个值为value数据Flux.just(value);//通过list创建一个流,往流上依次发布list中的数据Flux.fromIterable(list);//创建一个流,并向流上从i开始连续发布n个数据,数据类型为IntegerFlux.range(i, n);//创建一个流,并定时向流上发布一个数据,数据从0开始递增,数据类型为LongFlux.interval(Duration.ofSeconds(n));

既然是“数据流”的发布者,Flux和Mono都可以发出三种“数据信号”:元素值、错误信号、完成信号,错误信号和完成信号都是终止信号,完成信号用于告知下游订阅者该数据流正常结束,错误信号终止数据流的同时将错误传递给下游订阅者。

Subscriber

subscriber是一个订阅者,他只有非常简单的4个接口

publicinterfaceSubscriber<T>{voidonSubscribe(Subscription var1);//收到下一个元素值信号时的行为voidonNext(T var1);//收到错误信号时的行为voidonError(Throwable var1);//收到终止信号时的行为voidonComplete();}

Subscriber必须要订阅一个Flux才能够接收通知:

flux.subscribe(
    value->handleData(value),
    error->handleError(error),()->handleComplete());

WebFlux

参照资料:WebFlux 详解

Spring WebFlux 是一个异步非阻塞式 IO 模型,通过少量的容器线程就可以支撑大量的并发访问。底层使用的是 Netty 容器,这点也和传统的 SpringMVC 不一样,SpringMVC 是基于 Servlet 的。

Spring Framework 中包含的原始 Web 框架 Spring Web MVC 是专门为 Servlet API 和 Servlet 容器构建的。反应式堆栈 Web 框架 Spring WebFlux 是在 5.0 版的后期添加的。它是完全非阻塞的,支持反应式流(Reactive Stream)背压,并在Netty,Undertow和Servlet 3.1 +容器等服务器上运行。

  • WebFluxReactor 为基础,实现Web 领域的反应式编程框架
  • Reactor 是基于Reactive Streams 一套反应式编程框架
  • Reactive Stream 是一套反应式编程标准规范

LUA脚本

参考资料:Lua脚本语言

Lua天生的定位就是做为一门"胶水语言"出现的.它没有自己独立的环境, 必须依附在宿主语言的环境中才能起作用.所以从一开始,Lua就非常清楚自己的定 位:它不想自己做大,而是做的够精简够小,嵌入在宿主语言中,帮忙提供一些动态 特性

轻量级— 轻量级Lua语言的官方版本只包括一个精简的核心和最基本的 库。这使得Lua体积小、启动速度快,从而适合嵌入在别的程序里。5.0.2版的Lua 的内核小于120KB,而Python的内核大约860KB,Perl的内核大约1.1MB。
可扩展 —可扩展 Lua并不象其它许多"大而全"的语言那样,包括很多功 能,比如网络通讯、图形界面等。但是Lua提供了非常易于使用的扩展接口和机制:由宿主语言(通常是C或C++)提供这些功能,Lua可以使用它们,就像是本来就 内置的功能一样。
其它特性— 支持面向过程和面向对象;自动内存管理;

  • 作者:ONLY&YOU
  • 原文链接:https://blog.csdn.net/qq_34182808/article/details/124170164
    更新时间:2022年9月4日11:13:37 ,共 6053 字。