-
Notifications
You must be signed in to change notification settings - Fork 0
Keyed Rate Limiting
A KeyedRateLimiter manages independent token buckets for distinct keys (e.g., IP addresses, User IDs, API Keys). This allows you to apply the same rate limit rule individually to thousands or millions of entities.
To create a keyed limiter, you need both a TokenBucketSpec (the rule) and a KeyedStoreSpec (the storage config).
// Rule: 5 requests per second
TokenBucketSpec rateSpec = TokenBucketSpec.builder()
.capacity(5)
.refillTokens(5)
.refillPeriod(Duration.ofSeconds(1))
.build();
// Storage: Max 1000 users, expire after 1 hour idle
KeyedStoreSpec<String> storeSpec = KeyedStoreSpec.<String>builder()
.maxKeys(1000)
.evictionPolicy(EvictionPolicy.EXPIRE_AFTER_ACCESS)
.expireAfterAccess(Duration.ofHours(1))
.build();
KeyedRateLimiter<String> limiter = BucketGuards.keyedTokenBucket(rateSpec, storeSpec);Usage is identical to the standard limiter, but requires a key.
String ipAddress = request.getRemoteAddr();
if (limiter.tryAcquire(ipAddress).granted()) {
// allow
} else {
// deny
}By default, eviction policies like EXPIRE_AFTER_ACCESS are passive. A key is only removed when the map is accessed (during a read or write). If your application becomes idle, expired keys might linger in memory.
To strictly enforce expiration, you can schedule active maintenance.
- Enable maintenance in your spec:
.maintenanceEnabled(true) .maintenancePeriod(Duration.ofSeconds(30))
- Provide a scheduler to the limiter:
ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor(); limiter.startMaintenance(scheduler);
The limiter will now run a background task every 30 seconds (or your configured period) to prune expired keys.