I'm building an Java REST API that requires clients to use api keys in order to access. I want to implement rate limiting based on the API key, so that a single api cannot use the api too many times within a given timeframe. I'm been looking to using resilience4j for this, but I can't seem to find if resilience 4j supports implementing rate limiting based on criteria such as ip address or api key, instead of just rate limiting in general. Does anyone know if this possible, and or know of any resources that show how to do this? Thanks.
CodePudding user response:
You need to have a RateLimiter instance for each IP/apiKey instead of only one RateLimiter instance for all IP/apiKey.
See the guide below:
// Define one instance of LimiterManager ( Singleton | ApplicationScoped )
// NOTES: Reuse this instance
LimiterManager limiterManager = new LimiterManager();
String apiKey = "abc"; // // Get apiKey from current client request
final RateLimiter rateLimiter = limiterManager.getLimiter(apiKey);
// You can use other RateLimiter.decorateXXX depends on your logic
Runnable runnable = RateLimiter.decorateRunnable(rateLimiter, new Runnable() {
@Override
public void run() {
// TODO: Your allowed code here
}
});
Try.runRunnable(runnable).onFailure(
error -> System.out.print(error)
);
// Define LimiterManager utility class
public static class LimiterManager {
final ConcurrentMap<String, RateLimiter> keyRateLimiters = new ConcurrentHashMap<String, RateLimiter>();
final RateLimiterConfig config = RateLimiterConfig.custom().timeoutDuration(Duration.ofMillis(100))
.limitRefreshPeriod(Duration.ofSeconds(1))
.limitForPeriod(3) // Max 3 accesses per 1 second
.build();
public RateLimiter getLimiter(String apiKey) {
return keyRateLimiters.compute(apiKey, (key, limiter) -> {
return (limiter == null) ? RateLimiter.of(apiKey, config) : limiter;
});
}
}
CodePudding user response:
The problem with resilience4j is that it doesn't work with sharding, give a look at https://github.blog/2021-04-05-how-we-scaled-github-api-sharded-replicated-rate-limiter-redis/