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}"