Spring Cloud Gateway - 扩展

[TOC]


Spring Cloud Gateway的监控端点

说到监控,就应该能想到Spring Boot Actuator。而Spring Cloud Gateway基于Actuator提供了许多的监控端点。只需要在项目中添加spring-boot-starter-actuator依赖,并将 gateway 端点暴露,即可获得若干监控端点。配置示例:

management:
  endpoints:
    web:
      exposure:
        include: gateway  # 或者配置“*”暴露全部端点

Spring Cloud Gateway的监控端点如下表:

端点 请求方法 描述
globalfilters GET 展示所有的全局过滤器信息
routefilters GET 展示所有的过滤器工厂信息
refresh POST(无消息体) 清空路由缓存,即刷新路由信息
routes GET 展示所有的路由信息列表
routes/{id} GET 展示指定id的路由的信息
routes/{id} POST(有消息体) 新增一个路由
routes/{id} DELETE(无消息体) 删除一个路由

Gateway所有的监控端点都挂载在 /actuator/gateway 路径下,例如globalfilters端点的完整访问路径是 /actuator/gateway/globalfilters。该端点主要是查看Gateway启用了哪些全局过滤器以及它们的执行顺序(数字越小越优先执行)。所以当我们不知道Gateway启用了哪些全局过滤器,或者不知道这些全局过滤器的执行顺序,就可以访问该端点进行查看:

同理,如果不知道Gateway启用了哪些过滤器工厂,则可以访问routefilters端点查看:

若想知道Gateway里定义了哪些路由又不想查看配置文件的话,那么就可以通过routes端点查看所有的路由信息列表:

如果出现自定义的路由配置不生效或行为与预期不符,那么可以通过routes/{id}端点查看该路由具体的详细信息:

routes/{id}端点还可以用于动态添加路由,只需发送POST请求并定义一个消息体即可。消息体示例:

{
  "predicates": [
    {
      "name": "Path",
      "args": {
        "_genkey_0": "/test"
      }
    }
  ],
  "filters": [
    {
      "name": "AddRequestHeader",
      "args": {
        "_genkey_0": "X-Request-Foo",
        "_genkey_1": "Bar"
      }
    },
    {
      "name": "PreLog",
      "args": {
        "_genkey_0": "a",
        "_genkey_1": "b"
      }
    }
  ],
  "uri": "https://www.example.com",
  "order": 0
}

消息体其实是有规律的,你可以先在配置文件中配置一个路由规则,然后访问 routes 端点,route_definition字段里的内容就是消息体,如下:

接下来我们实际测试一下,复制该消息体,然后稍微修改一下并进行发送,如下:

路由添加成功后,访问 routes 端点,就可以看到新添加的路由:

注:如果没有实时生效,使用 refresh 端点刷新一下路由信息即可

官方文档:


关于Gateway的调试、排错

1、Gateway的监控端点:

上一小节介绍了Gateway的监控端点,这些监控端点可以帮助我们分析全局过滤器、过滤器工厂、路由详情等

2、日志:

设置一些相关包的日志级别,打印更详细的日志信息,可按需将如下包的日志级别设置成 debugtrace

  • org.springframework.cloud.gateway
  • org.springframework.http.server.reactive
  • org.springframework.web.reactive
  • org.springframework.boot.autoconfigure.web
  • reactor.netty
  • redisratelimiter

配置示例:

logging:
  level:
    org.springframework.cloud.gateway: trace

3、Wiretap Logger【需Greenwich SR3及更高版本才会支持】:

Reactor Netty的 HttpClient 以及 HttpServer 可启用 Wiretap。需将 reactor.netty 包设置成 debugtrace ,然后在配置文件中添加如下配置:

  • spring.cloud.gateway.httpserver.wiretap=true:开启 HttpServer 的Wiretap
  • spring.cloud.gateway.httpclient.wiretap=true:开启 HttpClient 的Wiretap

wiretap其实是Reactor Netty的概念,用于打印对端之间的流量详情,相关文档:


过滤器执行顺序

我们都知道全局过滤器使用@Order 注解或实现 Ordered 接口来配置一个决定执行顺序的数字,该数字越小的过滤器越靠前执行。

但是在路由规则上所配置的过滤器工厂并没有配置类似Order之类的东西,那么是如何决定执行顺序的呢?其实,过滤器工厂默认也会被设置一个Order,该Order按配置顺序从1开始递增,也是Order越小越靠前执行。如下:

routes:
  - id: test-route
    uri: lb://user-center
    predicates:
      - TimeBetween=上午9:00,下午5:00
    filters:
      # 按配置顺序从1开始递增
      - AddRequestHeader=Y-Header, Bar    # Order为1
      - AddResponseHeader=X-Header, Bar   # Order为2
      - PreLog=testName,testValue         # Order为3

使用default-filters配置的默认过滤器也是同理,但如果配置了默认过滤器,则会先执行相同Order的默认过滤器:

default-filters:
  - AddRequestHeader=Y-Foo, Bar    # Order为1
  - AddResponseHeader=X-Foo, Bar   # Order为2
routes:
  - id: test-route
    uri: lb://user-center
    predicates:
      - TimeBetween=上午9:00,下午5:00
    filters:
      # 按配置顺序从1开始递增
      - AddRequestHeader=Y-Header, Bar    # Order为1
      - AddResponseHeader=X-Header, Bar   # Order为2
      - PreLog=testName,testValue         # Order为3

如需自行控制过滤器工厂的Order,可返回OrderedGatewayFilter,如下示例:

@Slf4j
@Component
public class PreLogGatewayFilterFactory extends AbstractNameValueGatewayFilterFactory {

    @Override
    public OrderedGatewayFilter apply(NameValueConfig config) {
        return new OrderedGatewayFilter((exchange, chain) -> {
            ...
            return chain.filter(exchange);
        }, -1);
    }
}

核心代码:

  • org.springframework.cloud.gateway.route.RouteDefinitionRouteLocator#loadGatewayFilters:为过滤器设置了Order 数值,从1开始
  • org.springframework.cloud.gateway.route. RouteDefinitionRouteLocator#getFilters:加载默认过滤器 & 路由过滤器,并对过滤器做了排序
  • org.springframework.cloud.gateway.handler.FilteringWebH .andler#handle:构建过滤器链并执行

Spring Cloud Gateway跨域配置

Gateway支持CORS相关配置,可以通过不同的URL规则匹配不同的CORS策略。配置示例:

spring:
  cloud:
    gateway:
      globalcors:
        corsConfigurations:
          ‘[/**]‘:
            allowedOrigins: "http://docs.spring.io"
            allowedMethods:
            - GET

除此之外,还可以通过自定义过滤器来解决跨域问题,具体代码如下:

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.reactive.CorsWebFilter;
import org.springframework.web.cors.reactive.UrlBasedCorsConfigurationSource;
import org.springframework.web.util.pattern.PathPatternParser;

@Configuration
public class CorsConfig {

    @Bean
    public CorsWebFilter corsFilter() {
        CorsConfiguration config = new CorsConfiguration();
        config.addAllowedMethod("*");
        config.addAllowedOrigin("*");
        config.addAllowedHeader("*");

        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(new PathPatternParser());
        source.registerCorsConfiguration("/**", config);

        return new CorsWebFilter(source);
    }
}

Spring Cloud Gateway限流相关

在高并发的系统中,限流往往是一个绕不开的话题,我们都知道网关是流量的入口,所以在网关上做限流也是理所当然的。Spring Cloud Gateway内置了一个过滤器工厂,用于提供限流功能,这个过滤器工厂就是是RequestRateLimiterGatewayFilterFactory,该过滤器工厂基于令牌桶算法实现限流功能。

目前,该过滤器工厂默认使用 RedisRateLimiter 作为限速器,需要依赖Redis来存储限流配置,以及统计数据等。当然你也可以实现自己的RateLimiter,只需实现 org.springframework.cloud.gateway.filter.ratelimit.RateLimiter 接口,或者继承 org.springframework.cloud.gateway.filter.ratelimit.AbstractRateLimiter抽象类

Tips:

Redis Rate Limiter的实现基于这篇文章:Scaling your API with rate limiters
Spring官方引用的令牌桶算法文章:Token bucket

关于令牌桶之类的限流算法可以参考另一篇文章,这里就不过多赘述了:


动手实践

1、添加Redis依赖:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis-reactive</artifactId>
</dependency>

2、添加如下配置:

spring:
  cloud:
    gateway:
      routes:
        - id: user-center
          uri: lb://user-center
          predicates:
            - Path=/user-center/**
          filters:
            - StripPrefix=1
            - name: RequestRateLimiter
              args:
                # 令牌桶每秒填充平均速率
                redis-rate-limiter.replenishRate: 1
                # 令牌桶的上限
                redis-rate-limiter.burstCapacity: 2
                # 使用SpEL表达式从Spring容器中获取Bean对象
                key-resolver: "#{@pathKeyResolver}"
  # redis相关
  redis:
    host: 127.0.0.1
    port: 6379

3、编写一个KeyResolver,用于定义针对什么进行限流。例如按照访问路径限流,就写一个针对访问路径的KeyResolver;按照请求参数限流,那就写一个针对请求参数的KeyResolver,以此类推。这里我们按照访问路径限流,具体实现代码如下:

@Configuration
public class RaConfiguration {

    /**
     * 按照Path限流
     *
     * @return key
     */
    @Bean
    public KeyResolver pathKeyResolver() {
        return exchange -> Mono.just(
                exchange.getRequest()
                        // 获取path
                        .getPath()
                        .toString()
        );
    }
}

从代码的实现不难看出,实际就只是返回了一个访问路径,这样限流规则就会作用到访问路径上。例如访问:http://${GATEWAY_URL}/users/1,对于这个路径,它的redis-rate-limiter.replenishRate = 1redis-rate-limiter.burstCapacity = 2

访问:http://${GATEWAY_URL}/shares/1,对于这个路径,它的redis-rate-limiter.replenishRate = 1redis-rate-limiter.burstCapacity = 2;以此类推......

测试

接下来进行一个简单的测试,看看限流是否起作用了。持续频繁访问某个路径,当令牌桶的令牌被消耗完了,就会返回 429 这个HTTP状态码。如下:

然后迅速查看Redis中存储的key,会发现其格式如下:

从key的格式可以看出来,实际上 KeyResolver 的目的就是用来获取一个请求的唯一标识(这个标识可以是访问路径,可以是某个请求参数,总之就是可以从这个请求里获取出来的东西),并用其生成key以及解析key,以此实现针对性的限流。

拓展

如果请求会携带一个名为user的参数,其值为用户名,那么我们就可以通过这个请求参数来实现针对用户的限流。如下:

@Bean
public KeyResolver userKeyResolver() {
    return exchange -> Mono.just(
        exchange.getRequest()
            .getQueryParams()
            .getFirst("user")
    );
}

同理,我们还可以针对请求的来源IP进行限流。如下:

@Bean
public KeyResolver ipKeyResolver() {
    return exchange -> Mono.just(
      exchange.getRequest()
          .getHeaders()
          .getFirst("X-Forwarded-For")
    );
}

原文地址:https://blog.51cto.com/zero01/2430532

时间: 2024-10-09 05:03:47

Spring Cloud Gateway - 扩展的相关文章

Spring Cloud Gateway 结合配置中心限流

前言 假设你领导给你安排了一个任务,具体需求如下: 针对具体的接口做限流 不同接口限流的力度可以不同 可以动态调整限流配置,实时生效 如果你接到上面的任务,你会怎么去设计+实现呢? 每个人看待问题的角度不同,自然思考出来的方案也不同,正所谓条条大路通罗马,能到达目的地的路那就是一条好路. 如何分析需求 下面我给出我的实现方式,仅供各位参考,大牛请忽略. 具体问题具体分析,针对需求点,分别去做分析. 需求一 "如何针对具体的接口做限流" 这个在上篇文章中也有讲过,只需要让KeyResol

Spring Cloud Gateway入坑记

Spring Cloud Gateway入坑记 前提 最近在做老系统的重构,重构完成后新系统中需要引入一个网关服务,作为新系统和老系统接口的适配和代理.之前,很多网关应用使用的是Spring-Cloud-Netfilx基于Zuul1.x版本实现的那套方案,但是鉴于Zuul1.x已经停止迭代,它使用的是比较传统的阻塞(B)IO + 多线程的实现方案,其实性能不太好.后来Spring团队干脆自己重新研发了一套网关组件,这个就是本次要调研的Spring-Cloud-Gateway. 简介 Spring

API网关spring cloud gateway和负载均衡框架ribbon实战

通常我们如果有一个服务,会部署到多台服务器上,这些微服务如果都暴露给客户,是非常难以管理的,我们系统需要有一个唯一的出口,API网关是一个服务,是系统的唯一出口.API网关封装了系统内部的微服务,为客户端提供一个定制的API.客户端只需要调用网关接口,就可以调用到实际的微服务,实际的服务对客户不可见,并且容易扩展服务. API网关可以结合ribbon完成负载均衡的功能,可以自动检查微服务的状况,及时剔除或者加入某个微服务到可用服务列表.此外网关可以完成权限检查.限流.统计等功能.下面我们将一一完

最全面的改造Zuul网关为Spring Cloud Gateway(包含Zuul核心实现和Spring Cloud Gateway核心实现)

前言: 最近开发了Zuul网关的实现和Spring Cloud Gateway实现,对比Spring Cloud Gateway发现后者性能好支持场景也丰富.在高并发或者复杂的分布式下,后者限流和自定义拦截也很棒. 提示: 本文主要列出本人开发的Zuul网关核心代码以及Spring Cloud Gateway核心代码实现.因为本人技术有限,主要是参照了 Spring Cloud Gateway 如有不足之处还请见谅并留言指出. 1:为什么要做网关 (1)网关层对外部和内部进行了隔离,保障了后台服

第二代微服务网关组件 - Spring Cloud Gateway

[TOC] 初识Spring Cloud Gateway 简介: Spring Cloud Gateway是Spring Cloud体系的第二代网关组件,基于Spring 5.0的新特性WebFlux进行开发,底层网络通信框架使用的是Netty,所以其吞吐量高.性能强劲,未来将会取代第一代的网关组件Zuul.Spring Cloud Gateway可以通过服务发现组件自动转发请求,默认集成了Ribbon做负载均衡,以及默认使用Hystrix对网关进行保护,当然也可以选择其他的容错组件,例如Sen

spring cloud gateway获取response body

网关发起请求后,微服务返回的response的值要经过网关才发给客户端.本文主要讲解在spring cloud gateway 的过滤器中获取微服务的返回值,因为很多情况我们需要对这个返回进行处理.网上有很多例子,但是都没有解决我的实际问题,最后研究了下源码找到了解决方案. 本节内容主要从如下几个方面讲解,首先需要了解我的博文的内容:API网关spring cloud gateway和负载均衡框架ribbon实战 和 spring cloud gateway自定义过滤器 本文也将根据上面两个项目

Spring Cloud gateway 网关服务二 断言、过滤器

微服务当前这么火爆的程度,如果不能学会一种微服务框架技术.怎么能升职加薪,增加简历的筹码?spring cloud 和 Dubbo 需要单独学习.说没有时间?没有精力?要学俩个框架?而Spring Cloud alibaba只需要你学会一个就会拥有俩种微服务治理框架技术.何乐而不为呢?加油吧!骚猿年 上一篇我们讲述了gateway 的路由功能其实也类似与zuul服务的路由转发. 今天主要讲一下断言机制. 内置的断言工厂 介绍 Spring Cloud Gateway将路由作为Spring Web

微服务下使用网关 Spring Cloud Gateway

Spring Cloud Gateway 工作原理 客户端向 Spring Cloud Gateway 发出请求,如果请求与网关程序定义的路由匹配,则将其发送到网关 Web 处理程序,此处理程序运行特定的请求过滤器链. 过滤器之间用虚线分开的原因是过滤器可能会在发送代理请求之前或之后执行逻辑.所有 "pre" 过滤器逻辑先执行,然后执行代理请求,代理请求完成后,执行 "post" 过滤器逻辑. 如何启动 Spring Cloud Gateway 1.新建 Maven

Spring Cloud Gateway初体验

前段时间项目上打算使用gateway替换掉zuul1.0于是我简单的体验了一下. gateway是什么:Spring Cloud Gateway是Spring官方基于Spring 5.0,Spring Boot 2.0和Project Reactor等技术开发的网关,Spring Cloud Gateway旨在为微服务架构提供一种简单而有效的统一的API路由管理方式.这里需要注意一下gateway使用的netty+webflux实现,不要加入web依赖,需要加入webflux依赖. gatewa