このバージョンはまだ開発中であり、まだ安定しているとは見なされていません。最新の安定バージョンについては、Spring Cloud Gateway 4.3.2 を使用してください! |
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"));
}
有効な yaml 参照は次のとおりです。 application.yml |
Redis RateLimiter
Redis の実装は、ストライプ (英語) で行われた作業に基づいています。spring-boot-starter-data-redis-reactive Spring Boot スターターを使用する必要があります。
使用されるアルゴリズムはトークンバケットアルゴリズム [Wikipedia] (英語) です。
redis-rate-limiter.replenishRate プロパティは、許可する 1 秒あたりのリクエスト数を定義します (リクエストのドロップなし)。これは、トークンバケットが満たされる速度です。
redis-rate-limiter.burstCapacity プロパティは、ユーザーが 1 秒間に許可されるリクエストの最大数です (ドロップされたリクエストはありません)。これは、トークンバケットが保持できるトークンの数です。この値をゼロに設定すると、すべてのリクエストがブロックされます。
redis-rate-limiter.requestedTokens プロパティは、リクエストにかかるトークンの数です。これは、リクエストごとにバケットから取得されたトークンの数であり、デフォルトは 1 です。
replenishRate と burstCapacity に同じ値を設定すると、安定したレートが実現されます。burstCapacity を replenishRate より高く設定することにより、一時的なバーストを許可できます。この場合、2 つのバーストが連続するとリクエストが破棄される (HTTP 429 - Too Many Requests) ため、レートリミッタはバースト間にある程度の時間を許可する必要があります ( replenishRate に従って)。次のリストでは、redis-rate-limiter を構成しています。
1 request/s 未満のレート制限は、replenishRate を必要なリクエスト数に、requestedTokens を秒単位の時間範囲に、burstCapacity を replenishRate と requestedTokens の積に設定することで実現されます。例: 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 のバーストが許可されますが、次の 1 秒間は 10 のリクエストしか使用できません。KeyResolver は、user リクエストパラメーターを取得する単純なものです。注: これは本番環境では推奨されません。
バケット 4j RateLimiter
この実装はバケット 4j (英語) Java ライブラリに基づいています。com.bucket4j:bucket4j_jdk17-core 依存関係と、分散永続化オプション [GitHub] (英語) のいずれかを使用する必要があります。
この例では、ローカルキャッシュである 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 プロパティは、ユーザーが 1 秒間に許可するリクエストの最大数(ドロップされたリクエストを除く)です。これは、トークンバケットが保持できるトークンの数です。0 より大きい必要があります。
bucket4j-rate-limiter.refillPeriod プロパティは補充周期を定義します。バケットは refillPeriod ごとに refillTokens の割合で補充されます。これは必須プロパティであり、Spring Boot 期間形式を使用します。
bucket4j-rate-limiter.refillTokens プロパティは、refillPeriod 中にバケットに追加されるトークンの数を定義します。デフォルトは capacity で、0 以上である必要があります。
bucket4j-rate-limiter.requestedTokens プロパティは、リクエストにかかるトークン数です。これはリクエストごとにバケットから取得されるトークン数で、デフォルトは 1 です。0 より大きい値である必要があります。
bucket4j-rate-limiter.refillStyle プロパティは、バケットの補充方法を定義します。3 つのオプションは、GREEDY (デフォルト)、INTERVALLY、INTERVALLY_ALIGNED です。GREEDY は、トークンをできるだけ早くバケットに追加しようとします。INTERVALLY は、貪欲とは逆に、refillPeriod が経過するまでトークンを補充しません。INTERVALLY_ALIGNED は INTERVALLY に似ていますが、timeOfFirstRefill が指定されています。
bucket4j-rate-limiter.timeOfFirstRefill プロパティは、refillStyle が INTERVALLY_ALIGNED に設定されている場合にのみ使用される Instant です。
以下の例では、ユーザーあたりのリクエストレート制限を 10 に設定しています。バーストリクエストは 20 まで許可されますが、次の 1 秒間は 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}"