RateLimiter フィルター
RateLimiter フィルターは、バケット 4j (英語) を使用して、現在のリクエストの続行が許可されるかどうかを判断します。そうでない場合は、HTTP 429 - Too Many Requests
(デフォルト) のステータスが返されます。
このドキュメントを読む前に、Bucket4j の概念 (英語) を確認してください。
Bucket4j で使用されるアルゴリズムはトークンバケットアルゴリズム [Wikipedia] (英語) です。
このフィルターは、keyResolver
パラメーターとその他の Bucket4j 構成パラメーターを受け取ります。キーリゾルバーは java.util.Function<ServerRequest, String>
です。これにより、ユーザーはリクエストからあらゆる情報を抽出して、構成された Bucket4j ディストリビューション [GitHub] (英語) メカニズムのキーとして使用できるようになります。共通キーは、ServerRequest
から取得された Principal
になります。
デフォルトでは、キーリゾルバーがキーを見つけられない場合、リクエストは FORBIDDEN
ステータスで拒否されます。
現在、キーリゾルバーを構成する唯一の方法は、外部プロパティではなく、Java DSL を使用することです。 |
Bucket4j 分散構成
型 io.github.bucket4j.distributed.proxy.AsyncProxyManager
の Bean。これを行うには、ProxyManager.asAsync()
メソッドを使用します。
import com.github.benmanes.caffeine.cache.Caffeine;
import io.github.bucket4j.caffeine.CaffeineProxyManager;
@Configuration
class RateLimiterConfiguration {
@Bean
public AsyncProxyManager<String> caffeineProxyManager() {
Caffeine<String, RemoteBucketState> builder = (Caffeine) Caffeine.newBuilder().maximumSize(100);
return new CaffeineProxyManager<>(builder, Duration.ofMinutes(1)).asAsync();
}
}
上記は、テストに役立つローカルのメモリ内キャッシュである Caffeine
を使用して AsyncProxyManager
を構成します。
バケットの構成
デフォルトでは、バケットは構成済みの capacity
および period
を使用して構成されます。容量は、バケットに含まれるトークンの数です。期間は、バケット内で使用可能なトークンが再生成されるまでの期間を定義する java.util.Duration
です。
その他の構成項目は、リクエストが拒否されたときに返される statusCode
です。デフォルトでは 429、TO_MANY_REQUESTS です。tokens
項目は、各リクエストに使用されるトークンの数を定義し、デフォルトは 1 です。headerName
項目は、残りのトークンの数を含むヘッダーの名前で、デフォルトは X-RateLimit-Remaining
です。timeout
オプションは、分散バケットが応答を返すための Duration
を定義しますが、デフォルトでは設定されません。
次に、レート制限を使用したルートの設定例を示します。
import static org.springframework.cloud.gateway.server.mvc.filter.Bucket4jFilterFunctions.rateLimit;
import static org.springframework.cloud.gateway.server.mvc.handler.GatewayRouterFunctions.route;
import static org.springframework.cloud.gateway.server.mvc.handler.HandlerFunctions.http;
@Configuration
class RouteConfiguration {
@Bean
public RouterFunction<ServerResponse> gatewayRouterFunctionsRateLimited() {
return route("rate_limited_route")
.GET("/api/**", http("https://example.org"))
.filter(rateLimit(c -> c.setCapacity(100)
.setPeriod(Duration.ofMinutes(1))
.setKeyResolver(request -> request.servletRequest().getUserPrincipal().getName())))
.build();
}
}
これにより、1 分あたり 100 トークンのバケット容量でレート制限が構成されます。キーリゾルバーはサーブレットリクエストからプリンシパル名を取得します。