Spring Cloud Gateway限制API速率 - tanzu


软件架构师的当务之急之一是保护API和服务端点免受有害事件(例如拒绝服务攻击,级联故障或资源过度使用)的危害。速率限制是一种用于控制使用API​​或服务的速率的技术,它反过来可以保护您免受可能导致服务突然停止的这些事件的侵害。在分布式系统中,没有比集中配置和管理使用者与API交互的速率更好的选择了。只有在规定速率内的那些请求才可以进入API。否则将返回HTTP 429(“请求过多”)错误。
Spring Cloud Gateway是一个简单轻巧的组件,可用于限制API使用率。
在原始的Spring Boot应用程序中包括Spring Boot Cloud依赖项:org.springframework.cloud:spring-cloud-starter-gateway,无需任何代码即可在架构中包含Spring Cloud Gateway。
可以使用配置的路由定义将Spring Cloud Gateway从前端服务接收到的请求路由到后端服务,这将使网关清楚地知道应如何将请求路由到后端端点。路由配置通常基于可从HTTP请求中提取的信息(例如路径和标头)来定义条件。
下面的代码段列出了一个YAML节,用于配置将请求路由到后端服务的条件;它表明当路径中用“ / backend”命中网关时,请求应该以后端服务为目标。在配置中,为路由提供了一个标识符和后端服务URL。

spring:
  cloud:
    gateway:
      routes:
        - id: route1
          uri: http://localhost:8081
          predicates:
            - Path=/backend

 
RequestRateLimiter定义key
RequestRateLimiter是Spring Cloud Gateway提供的众多网关过滤器之一;它确定是允许进行请求还是已超过请求的限制。它还允许您(可选)插入key以限制对不同服务的请求数量。
在实现如何自定义key解析的同时,网关附带了一个利用用户Principal名的网关。需要一个安全的网关来解析用户的主体名称,但是您可以选择实现该KeyResolver接口以代替解析来自ServerWebExchange不同的key。
您可以使用表达式(例如,名为customKeyResolver)SPEL #{@customKeyResolver}指向配置中的自定义KeyResolverbean。下面显示了KeyResolver接口:
public interface KeyResolver {
    Mono<String> resolve(ServerWebExchange exchange);
}

如果没有key,网关将拒绝请求。要让网关不解析key,可以设置以下属性:
spring.cloud.gateway.filter.request-rate-limiter.deny-empty-key=false

您还可以通过设置以下属性,指定网关在找不到key时应报告的状态代码:
spring.cloud.gateway.filter.request-rate-limiter.empty-key-status-code=
 

速率限制器
假设网关通过使用Redis控制API消耗的限制。Redis使用令牌桶算法。要启用它,您需要在网关应用程序中包括Spring Boot启动程序依赖项spring-boot-starter-data-redis。
基本上,令牌桶算法使用余额令牌作为维持累积使用预算的一种方式。该算法假定令牌将以一定速率添加到存储桶中,而对API的调用会消耗存储桶中的令牌。一个API调用可以执行许多操作,以便组成一个响应,从而满足请求(基于GraphQL的API的想法)。在这种情况下,该算法可帮助Spring Cloud Gateway识别出一次调用可能花费一个API多个令牌。
提供的Redis实现使您可以定义请求速率,用户可以在特定时间段内以该速率进行调用。这也使得有可能适应零散的需求,同时受到定义的消耗率的限制。
例如,配置可以通过设置redis-rate-limiter.replenishRate=500属性来定义每秒500个请求的补充速率,并且可以通过设置属性redis-rate-limiter.burstCapacity=1000来定义每秒1,000个请求的突发容量。这样先会将消耗限制为每秒500个请求,如果请求数量突然增加,则仅允许1,000个请求。但是,由于这超出了我们定义的每秒500个请求的限制,因此网关将在下一秒才会路由其他500个请求。
该配置还允许您通过设置属性redis-rate-limiter.requestedTokens来定义一个请求将花费多少个令牌。通常,它设置为1。
要使用具有请求限制功能的网关,需要使用RequestRateLimiter网关过滤器对其进行配置。该配置可以指定参数来定义补充率,突发容量和请求花费的令牌数量。下面的示例说明了如何使用这些参数配置网关:
spring:
  cloud:
    gateway:
      routes:
        - id: route1
          uri: http://localhost:8081
          predicates:
            - Path=/backend
          filters:
          - name: RequestRateLimiter
            args:
              redis-rate-limiter.replenishRate: 500
              redis-rate-limiter.burstCapacity: 1000
              redis-rate-limiter.requestedTokens: 1

Spring Cloud Gateway可以灵活地定义您自己的自定义速率限制器实现;它提供了一个RateLimiter实现和定义bean的接口。可以使用SPEL表达式来配置速率限制器bean ,就像在自定义key解析器中一样。
例如,您可以定义一个名为beancustomRateLimiter的自定义速率限制器和一个名为customKeyResolver的自定义密钥解析器,并配置如下所示的路由:

@Bean
public KeyResolver customKeyResolver {
    return exchange -> ....  // returns a Mono of String
}
spring:
  cloud:
    gateway:
      routes:
        - id: route1
          uri: http://localhost:8081
          predicates:
            - Path=/backend
          filters:
          - name: RequestRateLimiter
            args:
              rate-limiter: "#{customRateLimiter}"
              key-resolver: "#{customKeyResolver}"

GitHub找到代码。