SpringCloud微服务网关gateway

news2024/11/23 11:02:07

SpringCloud微服务网关gateway

网关简介

大家都都知道在微服务架构中,一个系统会被拆分为很多个微服务。那么作为客户端要如何去调用这么多的微服务呢?

如果没有网关的存在,我们只能在客户端记录每个微服务的地址,然后分别去用。

这样的架构,会存在着诸多的问题:

  • 每个业务都会需要鉴权、限流、权限校验、跨域等逻辑,如果每个业务都各自为战,自己造轮子实现一遍,会很蛋疼,完全可以抽出来,放到一个统一的地方去做。

  • 如果业务量比较简单的话,这种方式前期不会有什么问题,但随着业务越来越复杂,比如淘宝、亚马逊打开一个页面可能会涉及到数百个微服务协同工作,如果每一个微服务都分配一个域名的话,一方面客户端代码会很难维护,涉及到数百个域名,另一方面是连接数的瓶颈,想象一下你打开一个APP,通过抓包发现涉及到了数百个远程调用,这在移动端下会显得非常低效。

  • 后期如果需要对微服务进行重构的话,也会变的非常麻烦,需要客户端配合你一起进行改造,比如商品服务,随着业务变的越来越复杂,后期需要进行拆分成多个微服务,这个时候对外提供的服务也需要拆分成多个,同时需要客户端配合你进行改造,非常蛋疼。

上面的这些问题可以借助API网关来解决。

Spring Cloud Gateway

网关作为流量的入口,常用的功能包括路由转发,权限校验,限流等。

Spring Cloud Gateway 是Spring Cloud官方推出的第二代网关框架,定位于取代 Netflix Zuul1.0。相比 Zuul 来说,Spring Cloud Gateway 提供更优秀的性能,更强大的有功能。

Spring Cloud Gateway 是由 WebFlux + Netty + Reactor 实现的响应式的 API 网关。它不能在传统的 servlet 容器中工作,也不能构建成 war 包**。**

Spring Cloud Gateway 旨在为微服务架构提供一种简单且有效的 API 路由的管理方式,并基于 Filter 的方式提供网关的基本功能,例如说安全认证、监控、限流等等。

官方文档:https://docs.spring.io/spring-cloud-gateway/docs/current/reference/html/

Spring Cloud Gateway 功能特征

  • 基于Spring Framework 5, Project Reactor 和 Spring Boot 2.0 进行构建;
  • 动态路由:能够匹配任何请求属性;
  • 支持路径重写;
  • 集成 Spring Cloud 服务发现功能(Nacos、Eruka);
  • 可集成流控降级功能(Sentinel、Hystrix);
  • 可以对路由指定易于编写的 Predicate(断言)和 Filter(过滤器);

1.1 核心概念

  • 路由(route)

路由是网关中最基础的部分,路由信息包括一个ID、一个目的URI、一组断言工厂、一组Filter组成。如果断言为真,则说明请求的URL和配置的路由匹配。

  • 断言(predicates)

Java8中的断言函数,SpringCloud Gateway中的断言函数类型是Spring5.0框架中的ServerWebExchange。断言函数允许开发者去定义匹配Http request中的任何信息,比如请求头和参数等。

  • 过滤器(Filter)

SpringCloud Gateway中的filter分为Gateway FilIer和Global Filter。Filter可以对请求和响应进行处理。

1.2 工作原理

执行流程大体如下:

  1. Gateway Client向Gateway Server发送请求
  2. 请求首先会被HttpWebHandlerAdapter进行提取组装成网关上下文
  3. 然后网关的上下文会传递到DispatcherHandler,它负责将请求分发给RoutePredicateHandlerMapping
  4. RoutePredicateHandlerMapping负责路由查找,并根据路由断言判断路由是否可用
  5. 如果过断言成功,由FilteringWebHandler创建过滤器链并调用
  6. 请求会一次经过PreFilter–微服务–PostFilter的方法,最终返回响应

Spring Cloud Gateway快速开始

依赖

<!-- gateway网关 -->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>

注意:会和spring-webmvc的依赖冲突,需要排除spring-webmvc

配置

定义了一个路由,请求进来之后,会匹配路由,就配置而言,假如访问过来的地址是,http://127.0.0.1:8088/sentinel-boot/basic/hello,根据predicates中的断言判断是否匹配当前路由,匹配的话,就经过这个路由设置的过滤器处理请求,这里的是/sentinel-boot/basic/hello 处理后变成/basic/hello,然后拼接转发地址http://127.0.0.1:8099/basic/hello

spring:
  application:
    name: api-gateway
  cloud:
    gateway:
      routes: # 路由数组[路由 就是指定当请求满足什么条件的时候转到哪个微服务]
        - id: product_route # 当前路由的标识, 要求唯一
          uri: http://127.0.0.1:8099 # 请求要转发到的地址
          order: 1 # 路由的优先级,数字越小级别越高
          predicates: # 断言(就是路由转发要满足的条件)
            - Path=/sentinel-boot/** # 当请求路径满足Path指定的规则时,才进行路由转发
          filters: # 过滤器,请求在传递过程中可以通过过滤器对其进行一定的修改
            - StripPrefix=1    # 转发之前去掉1层路径.

访问测试

一个简单的示例只需要配置和引入依赖即可,测试成功如下

集成nacos

依赖

        <!-- nacos服务注册与发现 -->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-loadbalancer</artifactId>
        </dependency>

配置和测试

spring:
  cloud:
    nacos:
      # 需要注意的是客户客户端会在此端口+1000的基础上获取通信端口,具体参考nacos安装中的几个端口
      server-addr: 61.171.5.6:30848
      discovery:
        username: nacos
        password: nacos
        register-enabled: false #一般会注册成服务提供者和消费者,如果不想成为服务提供者,这里设置false
    gateway:
      routes:
        - id: product_route
          uri: lb://nacos-producer # lb指的是从nacos中按照名称获取微服务,并遵循负载均衡策略
          predicates:
            - Path=/nacos-producer/**
          filters:
            - StripPrefix=1

测试成功,图就不贴了,http://127.0.0.1:8088/nacos-producer/product/123

简略配置

spring:
  cloud:
    nacos:
      # 需要注意的是客户客户端会在此端口+1000的基础上获取通信端口,具体参考nacos安装中的几个端口
      server-addr: 61.171.5.6:30848
      discovery:
        username: nacos
        password: nacos
        register-enabled: false #一般会注册成服务提供者和消费者,如果不想成为服务提供者,这里设置false

    gateway:
      discovery:
        locator:
          enabled: true


这时候,就发现只要按照网关地址/微服务/接口的格式去访问,就可以得到成功响应。

如果服务提供端server.servlet.context-path 配置开启了,你可以参考DiscoveryLocatorProperties添加额外的配置

路由断言工厂(Route Predicate Factories)配置

https://docs.spring.io/spring-cloud-gateway/docs/current/reference/html/#gateway-request-predicates-factories

作用: 当请求gateway的时候, 使用断言对请求进行匹配, 如果匹配成功就路由转发, 如果匹配失败就返回404

注意:多个断言,都返回true才算匹配

类型:内置,自定义

SpringCloud Gateway包括许多内置的断言工厂,所有这些断言都与HTTP请求的不同属性匹配。具体如下:

基于ZoneDatetime类型的断言工厂

此类型的断言根据时间做判断,主要有三个:

AfterRoutePredicateFactory: 接收一个日期参数,判断请求日期是否晚于指定日期

BeforeRoutePredicateFactory: 接收一个日期参数,判断请求日期是否早于指定日期

BetweenRoutePredicateFactory: 接收两个日期参数,判断请求日期是否在指定时间段内

ZonedDateTime.now()

匹配这个时间点之后的任意请求

        predicates:
        - After=2017-01-20T17:42:47.789-07:00[Asia/Shanghai]

匹配这个时间点之前的任意请求

        predicates:
        - Before=2017-01-20T17:42:47.789-07:00[America/Denver]

大致是这样,其他的看官方文档吧

基于地址的断言工厂

​ 基于请求中的X-Forwarded-For,一般如果是代理服务器过来的,此地址代表真实ip,总的含义就是ip在这个网段内,就匹配

- XForwardedRemoteAddr=192.168.1.1/24

大致意思同上

- RemoteAddr=192.168.1.1/24

基于Cookie的断言工厂

CookieRoutePredicateFactory:接收两个参数,cookie 名字和一个正则表达式。 判断请求

cookie是否具有给定名称且值与正则表达式匹配。

​ 这个就是cookie的key是chocolate,value和正则表达式 ch. 匹配

-Cookie=chocolate, ch.

基于Header的断言工厂

HeaderRoutePredicateFactory:接收两个参数,标题名称和正则表达式。 判断请求Header是否具有给定名称且值与正则表达式匹配。

 -Header=X-Request-Id, \d+  

基于Host的断言工厂

HostRoutePredicateFactory:接收一个参数,主机名模式。判断请求的Host是否满足匹配规则。

 -Host=**.testhost.org 

基于Method请求方法的断言工厂

MethodRoutePredicateFactory:接收一个参数,判断请求类型是否跟指定的类型匹配。

-Method=GET              

基于Path请求路径的断言工厂

PathRoutePredicateFactory:接收一个参数,判断请求的URI部分是否满足路径规则。

-Path=/foo/{segment}     

基于Query请求参数的断言工厂

QueryRoutePredicateFactory :接收两个参数,请求param和正则表达式, 判断请求参数是否具有给定名称且值与正则表达式匹配。

-Query=baz, ba.

基于路由权重的断言工厂

WeightRoutePredicateFactory:接收一个[组名,权重], 然后对于同一个组内的路由按照权重转发

routes:
    -id: weight_route1 
     uri: host1 
     predicates:
        -Path=/product/**
        -Weight=group3, 1
    -id: weight_route2 
    uri: host2 
    predicates:
        -Path=/product/**
        -Weight= group3, 9

自定义路由断言工厂

自定义路由断言工厂需要继承 AbstractRoutePredicateFactory 类,重写 apply 方法的逻辑。在 apply 方法中可以通过 exchange.getRequest() 拿到 ServerHttpRequest 对象,从而可以获取到请求的参数、请求方式、请求头等信息。

  • 必须spring组件 bean
  • 类必须加上RoutePredicateFactory作为结尾
  • 必须继承AbstractRoutePredicateFactory
  • 必须声明静态内部类 声明属性来接收 配置文件中对应的断言的信息
  • 需要结合shortcutFieldOrder进行绑定
  • 通过apply进行逻辑判断 true就是匹配成功 false匹配失败

注意: 命名需要以 RoutePredicateFactory 结尾

示例

这个示例中只接收一个参数,多个参数一般使用逗号分隔,通过shortcutFieldOrder接收,然后会初始化内置的Config,再然后就是在apply中判断是否通过,更多请参考org.springframework.cloud.gateway.handler.predicate.AbstractRoutePredicateFactory其他实现类

@Component
public class CheckAuthRoutePredicateFactory
        extends AbstractRoutePredicateFactory<CheckAuthRoutePredicateFactory.Config> {

    public CheckAuthRoutePredicateFactory() {
        super(CheckAuthRoutePredicateFactory.Config.class);
    }

    @Override
    public List<String> shortcutFieldOrder() {
        return Arrays.asList("name");
    }

    @Override
    public Predicate<ServerWebExchange> apply(CheckAuthRoutePredicateFactory.Config config) {
        return new GatewayPredicate() {
            @Override
            public boolean test(ServerWebExchange exchange) {

                if(config.getName().equals("xushu")){
                    return true;
                }
                return false;
            }

        };
    }


    // 用于接收配置文件中 断言的信息
    @Validated
    public static class Config {
        private String name;

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }
    }

}

配置

    gateway:s
      routes:
        - id: product_route
          uri: lb://nacos-producer # lb指的是从nacos中按照名称获取微服务,并遵循负载均衡策略
          predicates:
            - Path=/nacos-producer/**
            - CheckAuth=xushu2 # 对应示例中自定义的断言工厂
          filters:
            - StripPrefix=1

过滤器工厂( GatewayFilter Factories)配置

Gateway 内置了很多的过滤器工厂,我们通过一些过滤器工厂可以进行一些业务逻辑处理器,比如添加剔除响应头,添加去除参数等

如下图,请求分为转发前处理,和转发后处理

https://docs.spring.io/spring-cloud-gateway/docs/current/reference/html/#gatewayfilter-factories

过滤器工厂作用参数
AddRequestHeader为原始请求添加HeaderHeader的名称及值
AddRequestParameter为原始请求添加请求参数参数名称及值
AddResponseHeader为原始响应添加HeaderHeader的名称及值
DedupeResponseHeader剔除响应头中重复的值需要去重的Header名称及去重策略
Hystrix为路由引入Hystrix的断路器保护HystrixCommand 的名称
FallbackHeaders为fallbackUri的请求头中添加具体的异常信息Header的名称
PrefixPath为原始请求路径添加前缀前缀路径
PreserveHostHeader为请求添加一个preserveHostHeader=true 的 属 性,路由过滤器会检查该属性以决定是否要发送原始的Host
RequestRateLimiter用于对请求限流,限流算法为令牌桶keyResolver、rateLimiter、statusCode、denyEmptyKey、emptyKeyStatus
RedirectTo将原始请求重定向到指定的URLhttp状态码及重定向的url
RemoveHopByHopHeadersFilter为原始请求删除IETF组织规定的一系列Header默认就会启用,可以通过配置指定仅删除哪些Header
RemoveRequestHeader为原始请求删除某个HeaderHeader名称
RemoveResponseHeader为原始响应删除某个HeaderHeader名称
RewritePath重写原始的请求路径原始路径正则表达式以及重写后路径的正则表达式
RewriteResponseHeader重写原始响应中的某个HeaderHeader名称,值的正 则表达式,重写后的值
SaveSession在转发请求之前,强制执行WebSession::save 操作
secureHeaders为原始响应添加一系列起安全作用的响应头无,支持修改这些安全响应头的值
SetPath修改原始的请求路径修改后的路径
SetResponseHeader修改原始响应中某个Header的值Header名称,修改后的值
SetStatus修改原始响应的状态码HTTP 状态码,可以是数字,也可以是字符串
StripPrefix用于截断原始请求的路径使用数字表示要截断的路径的数量
Retry针对不同的响应进行重试retries、statuses、methods、series
RequestSize设置允许接收最大请求包的大 小。如果请求包大小超过设置的值,则返回 413 Payload TooLarge请求包大小,单位为字节,默认值为5M
ModifyRequestBody在转发请求之前修改原始请求体内容修改后的请求体内容
ModifyResponseBody修改原始响应体的内容修改后的响应体内容

参数、请求头,请求路径过滤器工厂

去除第一层路径,添加请求头,请求参数,再添加前缀路径

          filters:
            - StripPrefix=1
            - AddRequestHeader=X-Request-color, red  #添加请求头
            - AddRequestParameter=color, blue  # 添加请求参数
            - PrefixPath=/nacos-producer  # 添加前缀 对应微服务需要配置context-path
        

测试代码

http://127.0.0.1:8088/nacos-producer/product/test

@RestController
@RequestMapping("/product")
@Slf4j
public class ProductController {

    @Value("${server.servlet.context-path}")
    String context_path;

    @RequestMapping("/test")
    public String get(HttpServletRequest request,@RequestParam("color") String color) {
//        Thread.sleep(4000);
        // 测试添加请求头
        log.info(request.getHeader("X-Request-color"));
        // 测试添加请求参数
        log.info(color);
        // 测试添加前缀地址
        log.info(context_path);
        return "查询商品成功";
    }
}

日志

2022-11-17 14:34:59.833 - INFO --- [nio-8005-exec-6] c.s.p.controller.ProductController       : red
2022-11-17 14:35:00.935 - INFO --- [nio-8005-exec-6] c.s.p.controller.ProductController       : blue
2022-11-17 14:35:01.384 - INFO --- [nio-8005-exec-6] c.s.p.controller.ProductController       : /nacos-producer

重定向操作

            - RedirectTo=302, https://www.baidu.com/  #重定向到百度,请求最终没有到提供者端

自定义过滤工厂

同样的你可以参考官方的其他实现类

继承AbstractNameValueGatewayFilterFactory且我们的自定义名称必须要以GatewayFilterFactory结尾并交给spring管理。

@Component
public class CheckAuthGatewayFilterFactory
        extends AbstractGatewayFilterFactory<CheckAuthGatewayFilterFactory.Config> {


    public CheckAuthGatewayFilterFactory() {
        super(Config.class);
    }

    @Override
    public List<String> shortcutFieldOrder() {
        return Arrays.asList("value");
    }

    @Override
    public GatewayFilter apply(Config config) {
        return new GatewayFilter() {
            @Override
            public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
                String name=exchange.getRequest().getQueryParams().getFirst("name");

                if(StringUtils.isNotBlank(name)){
                    if(config.getValue().equals(name)){
                        return chain.filter(exchange);
                    }
                    else {
                        // 返回404
                        exchange.getResponse().setStatusCode(HttpStatus.NOT_FOUND);
                        return exchange.getResponse().setComplete();
                    }
                }
                // 正常请求
                return chain.filter(exchange);
            }
        };
    }


    public static class Config {
        private String value;

        public String getValue() {
            return value;
        }

        public void setValue(String value) {
            this.value = value;
        }
    }

}

- CheckAuth=xushu

全局过滤器

文档:https://docs.spring.io/spring-cloud-gateway/docs/current/reference/html/#global-filters

局部过滤器和全局过滤器区别:

局部:局部针对某个路由, 需要在路由中进行配置

全局:针对所有路由请求, 一旦定义就会投入使用

GlobalFilter 接口和 GatewayFilter 有一样的接口定义,只不过, GlobalFilter 会作用于所有路由。

LoadBalancerClientFilter

LoadBalancerClientFilter 会查看exchange的属性 ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR 的值(一个URI),如果该值的scheme是 lb,比如:lb://myservice ,它将会使用Spring Cloud的LoadBalancerClient 来将 myservice 解析成实际的host和port,并替换掉 ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR 的内容。

spring:
  cloud:
    gateway:
      routes:
      - id: order_route
        uri: lb://mall-order
        predicates:
        - Path=/order/**
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
    URI url = exchange.getAttribute(GATEWAY_REQUEST_URL_ATTR);
    String schemePrefix = exchange.getAttribute(GATEWAY_SCHEME_PREFIX_ATTR);
    if (url == null || (!"lb".equals(url.getScheme()) && !"lb".equals(schemePrefix))) {
        return chain.filter(exchange);
    }

    throw NotFoundException.create(use404, "Unable to find instance for " + url.getHost());
}

自定义全局过滤器

@Component
public class LogFilter implements GlobalFilter {
    Logger log= LoggerFactory.getLogger(this.getClass());

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {

        log.info(exchange.getRequest().getPath().value());
        return chain.filter(exchange);
    }
}

允许跨域访问

官方文档:https://docs.spring.io/spring-cloud-gateway/docs/current/reference/html/#cors-configuration

首先跨域是浏览器限制的,一般跨域是通过前端的标签 <link>元素<script>元素<img>元素<iframe>元素,点击后从一个网站跳转到另一个网站,或者jsonP跨域,域名或ip端口完全相同就不算跨域,当然这需要对应的网站是支持跨域的,这个一般需要在请求返回浏览器的响应头里告诉浏览器我是允许跨域的。

一般这个是一个全局配置,如果是secrity或者shiro一般是在单独的过滤器中设置,当然不集成授权框架,spring本身也支持有这样的全局配置,百度吧

        httpServletResponse.setHeader("Access-control-Allow-Origin", "*");
        httpServletResponse.setHeader("Access-Control-Allow-Methods", "GET,POST,OPTIONS,PUT,DELETE");
        httpServletResponse.setHeader("Access-Control-Allow-Headers", httpServletRequest.getHeader("Access-Control-Request-Headers"));

gateway直接可以在配置中配置跨域相关的配置,如下

允许https://docs.spring.io跨域过来的get请求

      globalcors:
        cors-configurations:
          '[/**]':
            allowedOrigins: "https://docs.spring.io"
            allowedMethods:
              - GET

允许所有来源的跨域

spring:
  cloud:
    gateway:
        globalcors:
          cors-configurations:
            '[/**]':
              allowedOrigins: "*"
              allowedMethods:
              - GET
              - POST
              - DELETE
              - PUT
              - OPTION

测试代码

在idea中点击浏览器图标打开这个文件即可

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="http://apps.bdimg.com/libs/jquery/1.9.1/jquery.min.js"></script>
</head>
<body>
    <input type="button" value="点击跨域" onclick="getData()">
    <script>
        function getData() {
            $.get('http://127.0.0.1:8088/nacos-producer/product/test',function(data){
                alert(data)
            });
        }
    </script>
</body>
</html>

springboot默认的方式实现跨域

@Configuration
public class CorsConfig {
    @Bean
    public CorsWebFilter corsFilter() {
        CorsConfiguration config = new CorsConfiguration();
        config.addAllowedMethod("*");   // 允许的method
        config.addAllowedOrigin("*");   // 允许的来源
        config.addAllowedHeader("*");   // 允许的请求头参数

        // 运行访问的资源, 这个代码是由于gateway是通过webflux提供服务的,此处需要添加这样的配置
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(new PathPatternParser());
        source.registerCorsConfiguration("/**", config);

        return new CorsWebFilter(source);
    }
}

访问日志记录

文档:https://docs.spring.io/spring-cloud-gateway/docs/current/reference/html/#reactor-netty-access-logs

要启用 Reactor Netty 访问日志,请设置-Dreactor.netty.http.server.accessLogEnabled=true,似乎不支持在配置文件中开启

总之gateway基于webflux提供访问,webflux又基于netty,这个配置就是开启请求日志的打印

如果需要记录到文件中,logback参考如下

    <appender name="accessLog" class="ch.qos.logback.core.FileAppender">
        <file>access_log.log</file>
        <encoder>
            <pattern>%msg%n</pattern>
        </encoder>
    </appender>
    <appender name="async" class="ch.qos.logback.classic.AsyncAppender">
        <appender-ref ref="accessLog" />
    </appender>

    <logger name="reactor.netty.http.server.AccessLog" level="INFO" additivity="false">
        <appender-ref ref="async"/>
    </logger>

日志大致上打印了请求时间,请求路径,响应码等信息,

超时时间配置

文档:https://docs.spring.io/spring-cloud-gateway/docs/current/reference/html/#http-timeouts-configuration

全局的超时时间

spring:
  cloud:
    gateway:
      httpclient:
        connect-timeout: 1000
        response-timeout: 5s

路由的超时时间

   - id: per_route_timeouts
        uri: https://example.org
        predicates:
          - name: Path
            args:
              pattern: /delay/{timeout}
        metadata:
          response-timeout: 200
          connect-timeout: 200

TLS和SSL支持

文档:https://docs.spring.io/spring-cloud-gateway/docs/current/reference/html/#tls-and-ssl

gateway整合sentinel流控降级

网关作为内部系统外的一层屏障, 对内起到一定的保护作用, 限流便是其中之一. 网关层的限流可以简单地针对不同路由进行限流, 也可针对业务的接口进行限流,或者根据接口的特征分组限流。

https://github.com/alibaba/Sentinel/wiki/%E7%BD%91%E5%85%B3%E9%99%90%E6%B5%81

基础示例

依赖

注意这里和端方文档引入的不一样,spring-cloud-alibaba-sentinel-gateway中包含了官方要求的sentinel-spring-cloud-gateway-adapter

SentinelGatewayFilter 实例以及 SentinelGatewayBlockExceptionHandler 实例的注入这个依赖SentinelSCGAutoConfiguration类中已经完成了,我们不需要重复注入

        <!--sentinel整合gateway  以前的版本adapter-->

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

        <!--sentinel的依赖-->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
        </dependency>

配置

spring:
  cloud:
    nacos:
      # 需要注意的是客户客户端会在此端口+1000的基础上获取通信端口,具体参考nacos安装中的几个端口
      server-addr: 61.171.5.6:30848
      discovery:
        username: nacos
        password: nacos
    #        register-enabled: false #一般会注册成服务提供者和消费者,如果不想成为服务提供者,这里设置false
    sentinel:
      transport:
        dashboard: 127.0.0.1:8858
        # 指定sentinel控制台获取应用数据的端口,被占用会端口号默认 +1,设置后还是会自动+1
        port: 8719
    gateway:
      enabled: true
      discovery:
        locator:
          lower-case-service-id: true
      routes:
        - id: product_route
          uri: lb://nacos-producer # lb指的是从nacos中按照名称获取微服务,并遵循负载均衡策略
          predicates:
            - Path=/nacos-producer/**
            - CheckAuth=xushu2
            #- After=2000-12-31T23:59:59.789+08:00[Asia/Shanghai]
            #- Header=X-Request-Id,\d+
            #- Method=GET
            #- Query=name,xushu|zhuge
            #- CheckAuth=xushu2
        #配置过滤器工厂
          filters:
            - StripPrefix=1
            - AddRequestHeader=X-Request-color, red  #添加请求头
            - AddRequestParameter=color, blue  # 添加请求参数
            - PrefixPath=/nacos-producer  # 添加前缀 对应微服务需要配置context-path
#            - RedirectTo=302, https://www.baidu.com/  #重定向到百度,请求最终没有到提供者端
            - CheckAuth=xushu
        # Add your routes here.
        - id: product_route # 无对应服务
          uri: lb://product
          predicates:
            - Path=/product/**
        - id: httpbin_route  # 无对应服务
          uri: https://httpbin.org
          predicates:
            - Path=/httpbin/**
          filters:
            - RewritePath=/httpbin/(?<segment>.*), /$\{segment} # 效果待定

测试

这里会以路由id作为资源名称,同样的需要这个资源被访问了才能够显示在控制台

网关的sentinel界面,控制台菜单和网关应用是有区别的

被限流后显示

修改默认的限流返回

基础示例中默认的返回是

{
    "code": 429,
    "message": "Blocked by Sentinel: ParamFlowException"
}

这个是来自com.alibaba.csp.sentinel.adapter.gateway.sc.callback.DefaultBlockRequestHandler处理器,和之前普通应用的处理器DefaultBlockExceptionHandler不同,由于网关是webflux的,这个处理器也是针对webflux

如果我们要自定义返回

配置

    sentinel:
      transport:
        dashboard: 127.0.0.1:8858
        # 指定sentinel控制台获取应用数据的端口,被占用会端口号默认 +1,设置后还是会自动+1
        port: 8719
      scg:
        fallback:
          mode: response # 选择“重定向”或“响应”。  `redirect` or `response`.
          response-body: '{"code":403,"mes":"限流了"}'

成功后如下

实现自定义处理器

@Configuration
public class GatewayConfig {

    @PostConstruct
    public void init(){

         BlockRequestHandler blockRequestHandler = new BlockRequestHandler() {
             @Override
             public Mono<ServerResponse> handleRequest(ServerWebExchange exchange, Throwable t) {

                 System.out.println(t);

                 HashMap<String,String> map=new HashMap<>();
                 map.put("code",HttpStatus.TOO_MANY_REQUESTS.toString());
                 map.put("message","限流了2");

                 // 自定义异常处理
                 return ServerResponse.status(HttpStatus.OK)
                         .contentType(MediaType.APPLICATION_JSON)
                         .body(BodyInserters.fromValue(map));
             }
         };

        GatewayCallbackManager.setBlockHandler(blockRequestHandler);

    }
}

本地设置流控规则

大致和我sentinel基础示例中流控规则的初始化方式一致,只不过规则类变了

    @PostConstruct
    public void initGatewayRules() {
        Set<GatewayFlowRule> rules = new HashSet<>();
        //resource:资源名称,可以是网关中的 route 名称或者用户自定义的 API 分组名称。
        //count:限流阈值
        //intervalSec:统计时间窗口,单位是秒,默认是 1 秒。
        rules.add(new GatewayFlowRule("order_route")
                .setCount(2)
                .setIntervalSec(1)
        );
        rules.add(new GatewayFlowRule("user_service_api")
                .setCount(2)
                .setIntervalSec(1)
        );

        // 加载网关规则
        GatewayRuleManager.loadRules(rules);
    }

网关限流配置项

官方文档:https://sentinelguard.io/zh-cn/docs/api-gateway-flow-control.html

其中网关限流规则 GatewayFlowRule 的字段解释如下:

  • resource:资源名称,可以是网关中的 route 名称或者用户自定义的 API 分组名称。

  • resourceMode:规则是针对 API Gateway 的 route(RESOURCE_MODE_ROUTE_ID)还是用户在 Sentinel 中定义的 API 分组(RESOURCE_MODE_CUSTOM_API_NAME),默认是 route。

  • grade:限流指标维度,同限流规则的 grade 字段。

  • count:限流阈值

  • intervalSec:统计时间窗口,单位是秒,默认是 1 秒。

  • controlBehavior:流量整形的控制效果,同限流规则的 controlBehavior 字段,目前支持快速失败和匀速排队两种模式,默认是快速失败。

  • burst:应对突发请求时额外允许的请求数目。

  • maxQueueingTimeoutMs:匀速排队模式下的最长排队时间,单位是毫秒,仅在匀速排队模式下生效。

  • paramItem
    

    :参数限流配置。若不提供,则代表不针对参数进行限流,该网关规则将会被转换成普通流控规则;否则会转换成热点规则。其中的字段:

    • parseStrategy:从请求中提取参数的策略,目前支持提取来源 IP(PARAM_PARSE_STRATEGY_CLIENT_IP)、Host(PARAM_PARSE_STRATEGY_HOST)、任意 Header(PARAM_PARSE_STRATEGY_HEADER)和任意 URL 参数(PARAM_PARSE_STRATEGY_URL_PARAM)四种模式。
    • fieldName:若提取策略选择 Header 模式或 URL 参数模式,则需要指定对应的 header 名称或 URL 参数名称。
    • pattern:参数值的匹配模式,只有匹配该模式的请求属性值会纳入统计和流控;若为空则统计该请求属性的所有值。(1.6.2 版本开始支持)
    • matchStrategy:参数值的匹配策略,目前支持精确匹配(PARAM_MATCH_STRATEGY_EXACT)、子串匹配(PARAM_MATCH_STRATEGY_CONTAINS)和正则匹配(PARAM_MATCH_STRATEGY_REGEX)。(1.6.2 版本开始支持)

用户可以通过 GatewayRuleManager.loadRules(rules) 手动加载网关规则,或通过 GatewayRuleManager.register2Property(property) 注册动态规则源动态推送(推荐方式)。

api分组限流

就是先配置那些请求路径属于哪个分组,然后根据分组配置规则

其他配置项说明

网关高可用

为了保证 Gateway 的高可用性,可以同时启动多个 Gateway 实例进行负载,在 Gateway 的上游使用 Nginx 或者 F5 进行负载转发以达到高可用。配置就不粘贴了,大致是这个意思

关联信息

  • 关联的主题:
  • 上一篇:
  • 下一篇:
  • image: 20221021/1
  • 转载自:

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/74090.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

word电子版签名

word电子版签名 问题 word如何实现电子版签名 解决方案一 1 在纸上使用签字笔签名并进行拍照 2 对图片进行使用电子扫描 对于图片进行使用电子扫描&#xff0c; 可选择的app与微信小程序较多&#xff0c;可自行选择&#xff0c;对于app&#xff0c; 笔者推荐全能扫描王&a…

康沣生物通过上市聆讯:年亏损过亿 高瓴与比邻星是股东

雷递网 雷建平 12月7日康沣生物科技&#xff08;上海&#xff09;股份有限公司&#xff08;简称&#xff1a;“康沣生物”&#xff09;日前通过聆讯&#xff0c;准备在港交所上市。年亏损过亿康沣生物是一家专注于冷冻消融微创介入治疗技术在心血管领域应用的企业。康沣生物CEO…

我的年度用户体验趋势报告——由 ChatGPT AI 撰写

Our yearly UX trends report, but written by the ChatGPT AI作为今年用户体验集体计划的一部分&#xff0c;我们刚刚发布了年度用户体验状态报告。只是为了好玩&#xff0c;我们想测试ChatGPT人工智能对新一年用户体验趋势的看法&#xff0c;看看哪些预测一致&#xff0c;哪些…

移植第二天知识点整理

一&#xff1a; uboot源码移植准备工作 1.在家目录下创建一个<demo>文件夹 2.将en.SOURCES-stm32mp1-openstlinux-5.10-dunfell-mp1-21-11-17_tar_v3.1.0.xz文件夹拷贝到demo目录下 3.对en.SOURCES-stm32mp1-openstlinux-5.10-dunfell-mp1-21-11-17_tar_v3.1.0.xz进行解…

探秘微信业务优化:DDD从入门到实践

引言 | 本文作者从微信团队维护的带货类项目所遇卡点出发&#xff0c;尝试用领域驱动设计方法&#xff08;简称DDD&#xff09;&#xff0c;保障在快节奏、多人协作的项目迭代中&#xff0c;维持系统的可维护性、可拓展性、高内聚低耦合和稳定性。作者首先剖解相关概念原理&…

福建师范大学Android Room 技术浅谈

福建师范大学Android Room 技术浅谈 ## 前提告知该文章是用作课程评分,本文内容虽为原创&#xff0c;但也有参考。 1.Room的背景简介 处理大量结构化数据的应用可极大地受益于在本地保留这些数据。最常见的使用场景是缓存相关的数据&#xff0c;这样一来&#xff0c;当设备无…

JVM虚拟机内存结构详解,一文带你学习完80%的知识

程序计数器 定义 Program Counter Register 程序计数器&#xff08;寄存器&#xff09; 作用&#xff1a;是记录下一条 jvm 指令的执行地址行号特点&#xff1a; 是线程私有的&#xff0c;随着线程创建而创建&#xff0c;随着线程销毁而销毁不会存在内存溢出是一块较小的内存…

CVPR 2019|APCNet:基于全局引导的局部匹配度自适应金字塔上下文网络

&#x1f3c6;本篇论文发现了一种全局引导的局部匹配度&#xff08;Global-guided Local Affinity (GLA))特征&#xff0c;用于构造上下文语义信息。基于此特性&#xff0c;作者设计了自适应上下文模块&#xff0c;构建自适应金字塔上下文网络&#xff08;APCNet&#xff09;。…

手工测试2年面临职场危机,3个月进阶自动化测试后,老板终于留我了...

​前言 从学校到职场已经3年时间了&#xff0c;大学学的计算机专业&#xff0c;最开始事项从事java开发的&#xff0c;最终被现实打败&#xff0c;然后就从事了软件测试&#xff0c;现在已近过去了2年&#xff0c;为什么说是2年了&#xff0c;大学毕业有一段空窗期&#xff0c…

大数据面试之HDFS常见题目

大数据面试之HDFS常见题目 HDFS常见题目 1 HDFS读流程和写流程 1.1 读流程&#xff08;下载&#xff09; 文字描述&#xff1a; ​ 客户端将要读取的文件路径发送给 NameNode&#xff0c;NameNode 获取文件的元信息&#xff08;主要是 block 的存放位置信息&#xff09;返回…

美团外卖推荐智能流量分发的实践与探索

总第548篇2022年 第065篇美团外卖推荐团队在推荐算法的长期落地实践中&#xff0c;针对外卖业务情境化特点对排序模型进行深入探索与优化。本文介绍了面向情境化建模的“情境细分统一模型”建模思路&#xff0c;通过用户行为序列建模以及专家网络两个模块的优化&#xff0c;实现…

简单实用:css+html绘制常见图表

提到绘制图表&#xff0c;大家可能想到ECharts&#xff0c;其实&#xff0c;一些简单的图表可以直接通过csshtml实现&#xff0c;下面手把手带大家绘制&#xff0c;初学者也能轻松掌握。 1 csshtml绘制柱形图 我们先写一个超简单的html文件。 <div class"bargraph&q…

多维数组地址映射问题的求解(3维、4维为例)——数据结构

在上篇我大概介绍了多维数组的地址映射问题&#xff0c;但是不够完善&#xff0c;很多朋友还没有彻底学会&#xff0c;表示很头疼。这一方面的总结确实比较少&#xff0c;而且也很麻烦&#xff0c;但是不要怕&#xff0c;看完我的总结&#xff0c;相信你一定会有一直醍醐灌顶的…

《2022中国PaaS市场研究及选型评估报告》正式发布

《中智观察》第1741篇推送作者&#xff1a;海比研究院编辑&#xff1a;晓晓编审&#xff1a;赵满头图来源&#xff1a;中国软件网从2006年概念兴起至今&#xff0c;云计算已经在国内走过整整十五年的历程。云计算的三大模式SaaS、PaaS、IaaS从陌生到熟悉&#xff0c;从研发到应…

ML Journal6—OpenCV中的GUI功能

图像入门这是将在本教程中使用的图像borz.jpgimport cv2 as cv import sysimg cv.imread(borz.jpg) if img is None:sys.exit("Could not read the file.") cv.imshow("Display Window", img) k cv.waitKey(0) if k ord("s"):cv.imwrite(&quo…

《自己动手写CPU》学习记录(5)——第5章/Part 1

目录 引言 致谢 流水线的数据相关问题 问题分析 RAW类型 1、相邻指令数据相关 2、间隔1条指令数据相关 3、间隔2条指令数据相关 修改后的代码 译码模块 指令执行模块 顶层模块 测试 测试代码 生成.data初始化文件 仿真结果 引言 随章节进度继续推进&#xff0c…

【视频】马尔可夫链原理可视化解释与R语言区制转换MRS实例|数据分享

原文链接&#xff1a;http://tecdat.cn/?p12280马尔可夫链是从一个“状态”&#xff08;一种情况或一组值&#xff09;跳到另一个“状态”的数学系统。本文介绍了马尔可夫链和一种简单的状态转移模型&#xff0c;该模型构成了隐马尔可夫模型&#xff08;HMM&#xff09;的特例…

近期方案研究总结(那些你用的到的排列组合)

方案一 这个方案只一个位置一个号码&#xff0c;标的物即一个位置八十期不重即可以切入&#xff0c;以这样的思路去进行扩充。 纬度一 两期重复形态为&#xff1a;11、22、33、44、55、66、77、88、99、1010。 数上升一形态为&#xff1a;12、23、34、45、56、67、78、89、910…

微服务框架 SpringCloud微服务架构 28 数据同步 28.6 测试同步功能

微服务框架 【SpringCloudRabbitMQDockerRedis搜索分布式&#xff0c;系统详解springcloud微服务技术栈课程|黑马程序员Java微服务】 SpringCloud微服务架构 文章目录微服务框架SpringCloud微服务架构28 数据同步28.6 测试同步功能28.6.1 直接开干28 数据同步 28.6 测试同步…

云安全系列5:2023 年需要了解的 40个云安全术语

云安全具有广泛而复杂的特点&#xff0c;它有许多特定的术语和首字母缩略词。我们在这里整理了一些云安全术语。将其用作指南&#xff0c;可帮助您了解云安全的细微差别并更便于学习相关内容。 Agent 代理是专门的软件包或应用程序&#xff0c;部署到设备或机器上以完成与安全…