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.