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() メソッドを使用します。

RateLimiterConfiguration.java
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 を定義しますが、デフォルトでは設定されません。

次に、レート制限を使用したルートの設定例を示します。

RouteConfiguration.java
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 トークンのバケット容量でレート制限が構成されます。キーリゾルバーはサーブレットリクエストからプリンシパル名を取得します。