RequestRateLimiter GatewayFilter 工厂

RequestRateLimiter GatewayFilter 工厂使用 RateLimiter 实现来确定当前请求是否允许继续。如果不允许,默认返回状态 HTTP 429 - Too Many Requests

此过滤器接受一个可选的 keyResolver 参数和限流器特有的参数(在本节后面描述)。

keyResolver 是一个实现 KeyResolver 接口的 bean。在配置中,使用 SpEL 按名称引用 bean。#{@myKeyResolver} 是一个引用名为 myKeyResolver 的 bean 的 SpEL 表达式。以下列表显示了 KeyResolver 接口

KeyResolver.java
public interface KeyResolver {
	Mono<String> resolve(ServerWebExchange exchange);
}

KeyResolver 接口允许可插拔的策略来派生限制请求的键。在未来的里程碑版本中,将有一些 KeyResolver 实现。

KeyResolver 的默认实现是 PrincipalNameKeyResolver,它从 ServerWebExchange 中检索 Principal 并调用 Principal.getName()

默认情况下,如果 KeyResolver 未找到键,则请求将被拒绝。您可以通过设置 spring.cloud.gateway.filter.request-rate-limiter.deny-empty-keytruefalse)和 spring.cloud.gateway.filter.request-rate-limiter.empty-key-status-code 属性来调整此行为。

以下示例在 Java 中配置 KeyResolver

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

RequestRateLimiter 无法通过“快捷方式”表示法进行配置。以下示例是无效的

application.properties
# INVALID SHORTCUT CONFIGURATION
spring.cloud.gateway.routes[0].filters[0]=RequestRateLimiter=2, 2, #{@userkeyresolver}

以下是一个有效的 yaml 引用

application.yml
spring:
  cloud:
    gateway:
      routes:
      - id: limit
        uri: https://example.org
        filters:
        - name: RequestRateLimiter
          args:
            key-resolver: "#{@userkeyresolver}"

Redis RateLimiter

Redis 实现基于 Stripe 完成的工作。它需要使用 spring-boot-starter-data-redis-reactive Spring Boot starter。

使用的算法是令牌桶算法

redis-rate-limiter.replenishRate 属性定义了每秒允许的请求数(不丢弃任何请求)。这是令牌桶的填充速率。

redis-rate-limiter.burstCapacity 属性是用户在单个秒内允许的最大请求数(不丢弃任何请求)。这是令牌桶可以容纳的令牌数。将此值设置为零将阻止所有请求。

redis-rate-limiter.requestedTokens 属性是一个请求消耗的令牌数。这是每个请求从桶中获取的令牌数,默认为 1

通过在 replenishRateburstCapacity 中设置相同的值来实现稳定速率。通过将 burstCapacity 设置得高于 replenishRate 可以允许临时突发。在这种情况下,限流器需要在突发之间留出一些时间(根据 replenishRate),因为连续两次突发会导致请求被丢弃(HTTP 429 - Too Many Requests)。以下列表配置了一个 redis-rate-limiter

通过将 replenishRate 设置为所需的请求数,将 requestedTokens 设置为以秒为单位的时间跨度,并将 burstCapacity 设置为 replenishRaterequestedTokens 的乘积来实现低于 1 request/s 的速率限制。例如,设置 replenishRate=1requestedTokens=60burstCapacity=60 会导致限制为 1 request/min

application.yml
spring:
  cloud:
    gateway:
      routes:
      - id: requestratelimiter_route
        uri: https://example.org
        filters:
        - name: RequestRateLimiter
          args:
            redis-rate-limiter.replenishRate: 10
            redis-rate-limiter.burstCapacity: 20
            redis-rate-limiter.requestedTokens: 1

这定义了每个用户的请求速率限制为 10。允许突发 20 个请求,但在下一秒,只有 10 个请求可用。KeyResolver 是一个简单的,它获取 user 请求参数 注意:不建议用于生产环境

Bucket4j RateLimiter

此实现基于 Bucket4j Java 库。它需要使用 com.bucket4j:bucket4j_jdk17-core 依赖项以及 分布式持久化选项之一。

在此示例中,我们将使用 Caffeine 集成,它是一个本地缓存。可以通过在您的依赖管理中包含 com.github.ben-manes.caffeine:caffeine 工件来添加。com.bucket4j:bucket4j_jdk17-caffeine 工件也需要导入。

pom.xml
<dependency>
  <groupId>com.github.ben-manes.caffeine</groupId>
  <artifactId>caffeine</artifactId>
  <version>${caffeine.version}</version>
</dependency>
<dependency>
  <groupId>com.bucket4j</groupId>
  <artifactId>bucket4j_jdk17-caffeine</artifactId>
  <version>${bucket4j.version}</version>
</dependency>

首先需要创建一个类型为 io.github.bucket4j.distributed.proxy.AsyncProxyMananger<String> 的 bean。

Config.java
@Bean
AsyncProxyManager<String> caffeineProxyManager() {
	Caffeine<String, RemoteBucketState> builder = (Caffeine) Caffeine.newBuilder().maximumSize(100);
	return new CaffeineProxyManager<>(builder, Duration.ofMinutes(1)).asAsync();
}

bucket4j-rate-limiter.capacity 属性是用户在单个秒内允许的最大请求数(不丢弃任何请求)。这是令牌桶可以容纳的令牌数。必须大于零。

bucket4j-rate-limiter.refillPeriod 属性定义了填充周期。桶以每 refillPeriod 填充 refillTokens 的速率填充。这是一个必需的属性,并使用 Spring Boot 周期格式

bucket4j-rate-limiter.refillTokens 属性定义了在 refillPeriod 期间添加到桶中的令牌数。此值默认为 capacity,并且必须大于或等于零。

bucket4j-rate-limiter.requestedTokens 属性是一个请求消耗的令牌数。这是每个请求从桶中获取的令牌数,默认为 1。必须大于零。

bucket4j-rate-limiter.refillStyle 属性定义了桶的填充方式。有 3 个选项:GREEDY(默认)、INTERVALLYINTERVALLY_ALIGNEDGREEDY 尽可能快地将令牌添加到桶中。INTERVALLY 与 greedy 相反,它会等到整个 refillPeriod 过去后才填充令牌。INTERVALLY_ALIGNED 类似于 INTERVALLY,但具有指定的 timeOfFirstRefill

bucket4j-rate-limiter.timeOfFirstRefill 属性是一个 Instant,仅当 refillStyle 设置为 INTERVALLY_ALIGNED 时使用。

以下示例定义了每个用户的请求速率限制为 10。允许突发 20 个请求,但在下一秒,只有 10 个请求可用。注意:不建议用于生产环境

application.yml
spring:
  cloud:
    gateway:
      routes:
      - id: requestratelimiter_route
        uri: https://example.org
        filters:
        - name: RequestRateLimiter
          args:
            bucket4j-rate-limiter.capacity: 20
            bucket4j-rate-limiter.refillTokens: 10
            bucket4j-rate-limiter.refillPeriod: 1s
            bucket4j-rate-limiter.requestedTokens: 1

自定义 RateLimiter

您还可以将限流器定义为实现 RateLimiter 接口的 bean。在配置中,您可以使用 SpEL 按名称引用该 bean。#{@myRateLimiter} 是一个引用名为 myRateLimiter 的 bean 的 SpEL 表达式。以下列表定义了一个使用上一个列表中定义的 KeyResolver 的限流器

application.yml
spring:
  cloud:
    gateway:
      routes:
      - id: requestratelimiter_route
        uri: https://example.org
        filters:
        - name: RequestRateLimiter
          args:
            rate-limiter: "#{@myRateLimiter}"
            key-resolver: "#{@userKeyResolver}"
© . This site is unofficial and not affiliated with VMware.