RequestRateLimiter GatewayFilter 工廠
RequestRateLimiter GatewayFilter 工廠使用 RateLimiter 實現來確定當前請求是否允許繼續。如果不允許,預設返回狀態 HTTP 429 - Too Many Requests。
此過濾器接受一個可選的 keyResolver 引數和限流器特有的引數(在本節後面描述)。
keyResolver 是一個實現 KeyResolver 介面的 bean。在配置中,使用 SpEL 按名稱引用 bean。#{@myKeyResolver} 是一個引用名為 myKeyResolver 的 bean 的 SpEL 表示式。以下列表顯示了 KeyResolver 介面
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-key(true 或 false)和 spring.cloud.gateway.filter.request-rate-limiter.empty-key-status-code 屬性來調整此行為。
以下示例在 Java 中配置 KeyResolver
@Bean
KeyResolver userKeyResolver() {
return exchange -> Mono.just(exchange.getRequest().getQueryParams().getFirst("user"));
}
|
application.properties
以下是一個有效的 yaml 引用 application.yml
|
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。
透過在 replenishRate 和 burstCapacity 中設定相同的值來實現穩定速率。透過將 burstCapacity 設定得高於 replenishRate 可以允許臨時突發。在這種情況下,限流器需要在突發之間留出一些時間(根據 replenishRate),因為連續兩次突發會導致請求被丟棄(HTTP 429 - Too Many Requests)。以下列表配置了一個 redis-rate-limiter
透過將 replenishRate 設定為所需的請求數,將 requestedTokens 設定為以秒為單位的時間跨度,並將 burstCapacity 設定為 replenishRate 和 requestedTokens 的乘積來實現低於 1 request/s 的速率限制。例如,設定 replenishRate=1、requestedTokens=60 和 burstCapacity=60 會導致限制為 1 request/min。
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
在此示例中,我們將使用 Caffeine 整合,它是一個本地快取。可以透過在您的依賴管理中包含 com.github.ben-manes.caffeine:caffeine 工件來新增。com.bucket4j:bucket4j_jdk17-caffeine 工件也需要匯入。
<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。
@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(預設)、INTERVALLY 和 INTERVALLY_ALIGNED。GREEDY 儘可能快地將令牌新增到桶中。INTERVALLY 與 greedy 相反,它會等到整個 refillPeriod 過去後才填充令牌。INTERVALLY_ALIGNED 類似於 INTERVALLY,但具有指定的 timeOfFirstRefill。
bucket4j-rate-limiter.timeOfFirstRefill 屬性是一個 Instant,僅當 refillStyle 設定為 INTERVALLY_ALIGNED 時使用。
以下示例定義了每個使用者的請求速率限制為 10。允許突發 20 個請求,但在下一秒,只有 10 個請求可用。注意:不建議用於生產環境
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 的限流器
spring:
cloud:
gateway:
routes:
- id: requestratelimiter_route
uri: https://example.org
filters:
- name: RequestRateLimiter
args:
rate-limiter: "#{@myRateLimiter}"
key-resolver: "#{@userKeyResolver}"