gateway网关的作用_gateway网关集群

2022-11-07 16:36:03 浏览数 (1)

大家好,又见面了,我是你们的朋友全栈君。

为啥要有网关

大型系统在设计之初就会拆分为多个微服务,客户不可能都按每个服务的服务器地址进行访问,因为每个服务对应一个指定的Url,人咋记那么多的地址,这样我们是不是需要一个统一的入口公开给客户,去解决这种调用问题,同时,AJAX虽说可以进行异步请求实现局部刷新,但是不能解决跨域对吧,之前我们怎么进行跨域处理的,用的是在controller层添加@CrossOrign注解,解决跨域问题。单体项目还好说,那么在微服务项目中可能又成千上百的服务,那我都要一个个加吗?而且有的服务还可能存在着没有controller层的问题,我在过滤器、拦截器层面进行业务设计,那不G了?能不能在一个统一的地方进行解决?为了在项目简化前端调用的逻辑,同时优化内部服务的相互调用,也能更好的保护内部服务,网关应运而生。

概述

其实说到底,网关就是给一个指定的URL,让内外部的业务调用使用这指定的URL从而简化调用,还可以进行权限验证与限流的操作

Spring Cloud Gateway网关(后面简称SCG)

基于Spring 5.0 以及 Spring boot 2.0和一堆技术进行开发的一个网关组件,跟概述一样,作用提供一个指定的API入口,负责服务请求路由、结合、协议转换,并且基于过滤链可以提供权限认证与监控限流等功能

优缺点

优:性能厉害(是zuul的1.6倍zuul,zuul可处理百万并发)、

功能强大(内置了很多使用功能,例如限流与转发、监控),

好拓展

缺:依赖于Netty(网络通讯框架比Tomcat更牛可处理大量并发)与WebFlux(基于的是大量的异步通讯机制),跟之前的serverlet编程模型不同

需要Springboot 2.0以上才能用

webFlux的优点

就是tomcat接到一个请求之后,会从线程池中拿一个线程进行,服务于这个请求,Tomcat的线程池中的线程数是有限的,但是现在的这个线程接完请求之后还有对其进行处理,处理完请求后,才将线程放回池中,循环执行。但当Tomcat线程都在处理业务的时候,就会出现线程数不够的情况就不会再接请求了。而这个WebFlux就可实现Tomcat的线程只接受请求,处理业务的时候尽量交给后面的线程进行操作,解决这个问题。

使用gateway

1.创建一个网关服务模块 例sca-gateway

2.添加依赖:(注意添加了gateway依赖以后,不能添加spring web会冲突)

代码语言:javascript复制
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-gateway</artifactId>
        </dependency>

3.编写bootstrap.yml

首先配置路由元素,写好要被网关管理的服务的地址,当你的请求发过来的时候,首先要经过断言predicates,判断端口号与端口号后面的东西,如果和写的请求规则相同,然后进行过滤,去掉指定的路径,这里用到的过滤器是局部过滤器

代码语言:javascript复制
spring:
  application:
    name: sca-gateway
  cloud:
    gateway:
      routes:  #路由元素,此元素下可以有多个路由
       - id: route01
         uri: http://localhost:8081/  # 网关帮我们转发的的url  URL是URI的一个子集
         predicates: ### 断言(谓词)匹配请求规则  定义请求转发逻辑的,满足下面的条件才会被转发
           - Path=/nacos/provider/echo/**  #请求路径定义,此路径对应uri中的资源
         filters: #过滤器特殊的拦截器,写到这个位置的是局部过滤器
           - StripPrefix=1  # 过滤掉path中的第一层路径,例如nacos
server:
  port: 9000

知识点:URL是URI的一个子集,uri统一资源标识 url统一资源定位

知识点:NoSuchBeanDefintionException 找不到bean的异常

知识点:- Path=/nacos/provider/echo/** 两个星号代表着可以/a/v/b/c/… 单个标识/a

Gateway的负载均衡设计

负载均衡?

因为网关是一个请求的统一入口,要处理超高并发量的请求,所有的服务都会在网关层面进行底层的一个映射,所以在访问服务的时要基于服务serviceId 服务名去查找对应的服务,让请求从网关层实现负载均衡转发,以平衡服务实例的处理能力

Netty为什么性能这么好为什么不都用Netty,因为Netty是一个网络编程框架因此就需要二次开发!web依赖简单好用

Gateway中负载均衡实现

第一步:项目中添加服务发现依赖,为的是去发现网关可以访问的服务具体地址

lb是一个网关层面的协议名,底层也是基于ribbon实现

代码语言:javascript复制
server:
  port: 9000
spring:
  application:
    name: sca-gateway
  cloud:
    gateway:
      routes: #配置网关路由规则
        - id: route01  #路由id,自己指定一个唯一值即可
          uri: lb://sca-provider  #lb为服务前缀(负载均衡单词的缩写),不能随意写
          predicates: ###断言(谓词):匹配请求规则
            - Path=/nacos/provider/echo/**  #请求路径定义,此路径对应uri中的资源
          filters: ##网关过滤器,用于对谓词中的内容进行判断分析以及处理
            - StripPrefix=1 #转发之前去掉path中第一层路径,例如nacos
      discovery:
        locator:
          enabled: true  #开启通过服务注册中心的serviceId创建路由
    nacos:
      discovery:
        server-addr: localhost:8848

其次记得在配置文件把gateway日志打开

logging: level: com.jt: debug

第二步:启动多个provider进行测试

Gateway的执行流程

首先Gateway Client会发起请求,会有一个RoutePredicateHandlerMapping,根据你的url去获取对应的handler(处理器),但在去找handler之前要对其url进行校验,校验的就是我们在yml里设置的断言,首先回去断言工程创建GatewayPredicate对象,然后执行该对象中的test方法,返回值为boolean,当返回true的时候,会去寻找其handler,这里调用的是FilterWebHandler,这个处理器会去调用GatewayFilter也就是一个自定义的过滤链chain(责任链模式),也就是局部过滤器,之后再走全局过滤器,在其中实现负载均衡(ribbon),之后再进入对应的服务

断言增强分析

predicate断言又称作为谓词,只有当断言结果都为真的时候,才会执行真正的路由,也就是判断是否能进行路由转发的规则,Gateway所有的谓词都时间接或者直接的实现了RoutePredicateFactory接口,这些工厂负责创建谓词对象,或者通过谓词对象来判断请求合法性。

如何创建全局过滤器(针对所有的请求)

举个栗子:

创建一个类命名为AuthGlobalFilter,要去实现一个全局过滤器的标准(GlobalFilter 接口)

重写其中的filter(exchange,chain【过滤链】)(返回值是一个Mono)方法,进行自定义过滤器。

  1. 获取请求对象/响应对象:
    1. 获取请求使用的是filter方法中的exchange参数点出来的getRequest(),默认获取所有请求参数、还可以获取第一个、与指定的某个 get的是获取指定的,getFirst获取第一个
    2. exchange.getResponse();可以获取一个响应对象,然后可以设置其响应码等数据
  2. 获取请求中数据/设置响应中的数据
  3. 对请求数据进行分析处理
  4. 认证成功与失败
    1. 成功 返回 chain.filter(交互对象exchange);继续向后执行

具体实现一个小业务设置网关的黑名单不通过sentinel: 1.首先写yml文件(指定黑名单 -就是一个分隔符,会自动存到一个list集合中)

2.写具体的全局过滤器

两种可以获取对应yml文件中的值

  1. @Value(“web.request.blackUrls”)
  2. 在这个接口上添加@ConfigurationProperties(“web.request”)
    1. 当系统底层读取@ConfigurationProperties(prefix = “web.request”),注解中描述的内容时,会自动基于名字调用set方法 @param blackPaths
    2. 要记得去写set方法
代码语言:javascript复制
package com.jt.config;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.net.URI;
import java.util.ArrayList;
import java.util.List;
@ConfigurationProperties("web.request")
@Component
public class urlGlobalFilter  implements GlobalFilter {
    List<String> list = new ArrayList<>();

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpRequest request = exchange.getRequest();
        String uri = request.getURI().toString();
        System.out.println(list);
        for (String l1:list){
            if (uri.contains(l1)){
                    ServerHttpResponse response = exchange.getResponse();
                    response.setStatusCode(HttpStatus.UNAUTHORIZED);
                    return response.setComplete();
            }
        }
        return chain.filter(exchange);
    }

    /*
    * 当系统底层读取@ConfigurationProperties(prefix = "web.request")
    * 注解中描述的内容时,会自动基于名字调用set方法
    * @param blackPaths
    * */

    public void setList(List<String> blackPaths){
        this.list = blackPaths;
    }
}

Gateway的网关限流设计及其实现(细水长流)

为啥要设置网关,因为网关是访问服务的唯一入口,所以要处理高并发的访问

Burst size :0 请求瞬时并发是否允许额外的请求通过网关

实现步骤

【1】导入依赖,与其他正常服务的sentinel依赖有所不同

代码语言:javascript复制
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
        </dependency>


        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-alibaba-sentinel-gateway</artifactId>
        </dependency>

【2】在启动参数上添加

【3】sentinel的降级设定与正常服务添加一样

【4】设置降级可以分为api组限流与routeid限流

routeId限流就是根据你在yml的route一样

api分组,是可以把一些请求链路放在一起,进行批量设置

【5】api分组设置步骤

【6】设置流控规则

【7】根据指定的参数进行限流(举个栗子,用请求头里面的参数进行匹配,匹配到,就会执行对应的限流规则)

【8】当你想响应的值不为默认的,就要写这么一个配置类,来指定限流异常处理器

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员栈长,转载请注明出处:https://javaforall.cn/183079.html原文链接:https://javaforall.cn

0 人点赞