Update ratelimiter.adoc for Bucket4j rate limiter.
This commit is contained in:
@@ -92,7 +92,7 @@
|
||||
*** xref:spring-cloud-gateway-server-mvc/filters/removerequestparameter.adoc[]
|
||||
*** xref:spring-cloud-gateway-server-mvc/filters/removeresponseheader.adoc[]
|
||||
*** xref:spring-cloud-gateway-server-mvc/filters/requestheadersize.adoc[]
|
||||
*** xref:spring-cloud-gateway-server-mvc/filters/requestratelimiter.adoc[]
|
||||
*** xref:spring-cloud-gateway-server-mvc/filters/ratelimiter.adoc[]
|
||||
*** xref:spring-cloud-gateway-server-mvc/filters/rewritelocationresponseheader.adoc[]
|
||||
*** xref:spring-cloud-gateway-server-mvc/filters/rewritepath.adoc[]
|
||||
//*** xref:spring-cloud-gateway-server-mvc/filters/rewriterequestparameter.adoc[]
|
||||
|
||||
@@ -0,0 +1,69 @@
|
||||
[[ratelimiter-filter]]
|
||||
= RateLimiter Filter
|
||||
|
||||
The RateLimiter Filter use https://bucket4j.com/[Bucket4j] to determine if the current request is allowed to proceed. If it is not, a status of `HTTP 429 - Too Many Requests` (by default) is returned.
|
||||
|
||||
Please review https://bucket4j.com/8.7.0/toc.html#concepts[Bucket4j Concepts] prior to reading this documentation.
|
||||
|
||||
The algorithm used by Bucket4j is the https://en.wikipedia.org/wiki/Token_bucket[Token Bucket Algorithm].
|
||||
|
||||
The filter takes a `keyResolver` parameter and other Bucket4j configuration parameters. The key resolver is a `java.util.Function<ServerRequest, String>`. This allows the user to extract any information out of the request to use as a key in the configured https://github.com/bucket4j/bucket4j#bucket4j-distributed-features[Bucket4j distribution] mechanism. A common key would be the `Principal` retrieved from the `ServerRequest`.
|
||||
|
||||
By default, if the key resolver does not find a key, requests are denied with the `FORBIDDEN` status.
|
||||
|
||||
NOTE: Currently, the only way to configure key resolvers is through the Java DSL and not through external properties.
|
||||
|
||||
== Bucket4j Distributed Configuration
|
||||
|
||||
A bean of type `io.github.bucket4j.distributed.proxy.AsyncProxyManager`. To do this, use the `ProxyManager.asAsync()` method.
|
||||
|
||||
.RateLimiterConfiguration.java
|
||||
[source,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();
|
||||
}
|
||||
}
|
||||
----
|
||||
|
||||
The above configures an `AsyncProxyManager` using `Caffeine`, a local in-memory cache, useful for testing.
|
||||
|
||||
== Configuring Buckets
|
||||
|
||||
By default, the Bucket is configured using a configured `capacity` and `period`. Capacity is how many tokens the bucket has. The period is a `java.util.Duration` that defines how long for the tokens available in the bucket to be regenerated.
|
||||
|
||||
Other configuration items are the `statusCode` returned when the request is denied. By default it is 429, TO_MANY_REQUESTS. The `tokens` item defines how many tokens are used for each request and defaults to 1. The `headerName` item is the name of the header that contains the number of remaining tokens, this defaults to `X-RateLimit-Remaining`. The `timeout` option defines a `Duration` for the distributed bucket to return an answer and is not set by default.
|
||||
|
||||
The following is an example of configuring a route with rate limiting:
|
||||
|
||||
.RouteConfiguration.java
|
||||
[source,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();
|
||||
}
|
||||
}
|
||||
----
|
||||
|
||||
This configures the rate limiting with a bucket capacity of 100 tokens per minute. The key resolver gets the principle name from the Servlet request.
|
||||
@@ -1,120 +0,0 @@
|
||||
[[requestratelimiter-filter]]
|
||||
= `RequestRateLimiter` Filter
|
||||
|
||||
The `RequestRateLimiter` filter uses a `RateLimiter` implementation to determine if the current request is allowed to proceed. If it is not, a status of `HTTP 429 - Too Many Requests` (by default) is returned.
|
||||
|
||||
This filter takes an optional `keyResolver` parameter and parameters specific to the rate limiter (described xref:spring-cloud-gateway/gatewayfilter-factories/requestratelimiter-factory.adoc#key-resolver-section[later in this section]).
|
||||
|
||||
`keyResolver` is a bean that implements the `KeyResolver` interface.
|
||||
In configuration, reference the bean by name using SpEL.
|
||||
`#{@myKeyResolver}` is a SpEL expression that references a bean named `myKeyResolver`.
|
||||
The following listing shows the `KeyResolver` interface:
|
||||
|
||||
.KeyResolver.java
|
||||
[source,java]
|
||||
----
|
||||
public interface KeyResolver {
|
||||
Mono<String> resolve(ServerWebExchange exchange);
|
||||
}
|
||||
----
|
||||
|
||||
[[key-resolver-section]]
|
||||
The `KeyResolver` interface lets pluggable strategies derive the key for limiting requests.
|
||||
In future milestone releases, there will be some `KeyResolver` implementations.
|
||||
|
||||
The default implementation of `KeyResolver` is the `PrincipalNameKeyResolver`, which retrieves the `Principal` from the `ServerWebExchange` and calls `Principal.getName()`.
|
||||
|
||||
By default, if the `KeyResolver` does not find a key, requests are denied.
|
||||
You can adjust this behavior by setting the `spring.cloud.gateway.filter.request-rate-limiter.deny-empty-key` (`true` or `false`) and `spring.cloud.gateway.filter.request-rate-limiter.empty-key-status-code` properties.
|
||||
|
||||
[NOTE]
|
||||
=====
|
||||
The `RequestRateLimiter` is not configurable with the "shortcut" notation. The following example below is _invalid_:
|
||||
|
||||
.application.properties
|
||||
----
|
||||
# INVALID SHORTCUT CONFIGURATION
|
||||
spring.cloud.gateway.routes[0].filters[0]=RequestRateLimiter=2, 2, #{@userkeyresolver}
|
||||
----
|
||||
=====
|
||||
|
||||
[[redis-ratelimiter]]
|
||||
== The Redis `RateLimiter`
|
||||
|
||||
The Redis implementation is based on work done at https://stripe.com/blog/rate-limiters[Stripe].
|
||||
It requires the use of the `spring-boot-starter-data-redis-reactive` Spring Boot starter.
|
||||
|
||||
The algorithm used is the https://en.wikipedia.org/wiki/Token_bucket[Token Bucket Algorithm].
|
||||
|
||||
The `redis-rate-limiter.replenishRate` property defines how many requests per second to allow (without any dropped requests).
|
||||
This is the rate at which the token bucket is filled.
|
||||
|
||||
The `redis-rate-limiter.burstCapacity` property is the maximum number of requests a user is allowed in a single second (without any dropped requests).
|
||||
This is the number of tokens the token bucket can hold.
|
||||
Setting this value to zero blocks all requests.
|
||||
|
||||
The `redis-rate-limiter.requestedTokens` property is how many tokens a request costs.
|
||||
This is the number of tokens taken from the bucket for each request and defaults to `1`.
|
||||
|
||||
A steady rate is accomplished by setting the same value in `replenishRate` and `burstCapacity`.
|
||||
Temporary bursts can be allowed by setting `burstCapacity` higher than `replenishRate`.
|
||||
In this case, the rate limiter needs to be allowed some time between bursts (according to `replenishRate`), as two consecutive bursts results in dropped requests (`HTTP 429 - Too Many Requests`).
|
||||
The following listing configures a `redis-rate-limiter`:
|
||||
|
||||
Rate limits below `1 request/s` are accomplished by setting `replenishRate` to the wanted number of requests, `requestedTokens` to the timespan in seconds, and `burstCapacity` to the product of `replenishRate` and `requestedTokens`.
|
||||
For example, setting `replenishRate=1`, `requestedTokens=60`, and `burstCapacity=60` results in a limit of `1 request/min`.
|
||||
.application.yml
|
||||
[source,yaml]
|
||||
----
|
||||
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
|
||||
|
||||
----
|
||||
|
||||
The following example configures a `KeyResolver` in Java:
|
||||
|
||||
.Config.java
|
||||
[source,java]
|
||||
----
|
||||
@Bean
|
||||
KeyResolver userKeyResolver() {
|
||||
return exchange -> Mono.just(exchange.getRequest().getQueryParams().getFirst("user"));
|
||||
}
|
||||
----
|
||||
|
||||
This defines a request rate limit of 10 per user. A burst of 20 is allowed, but, in the next second, only 10 requests are available.
|
||||
The `KeyResolver` is a simple one that gets the `user` request parameter
|
||||
NOTE: This is not recommended for production
|
||||
|
||||
You can also define a rate limiter as a bean that implements the `RateLimiter` interface.
|
||||
In configuration, you can reference the bean by name using SpEL.
|
||||
`#{@myRateLimiter}` is a SpEL expression that references a bean with named `myRateLimiter`.
|
||||
The following listing defines a rate limiter that uses the `KeyResolver` defined in the previous listing:
|
||||
|
||||
.application.yml
|
||||
[source,yaml]
|
||||
----
|
||||
spring:
|
||||
cloud:
|
||||
gateway:
|
||||
routes:
|
||||
- id: requestratelimiter_route
|
||||
uri: https://example.org
|
||||
filters:
|
||||
- name: RequestRateLimiter
|
||||
args:
|
||||
rate-limiter: "#{@myRateLimiter}"
|
||||
key-resolver: "#{@userKeyResolver}"
|
||||
|
||||
----
|
||||
|
||||
Reference in New Issue
Block a user