Skip to content

Keyed Rate Limiting

frosxt edited this page Jan 19, 2026 · 1 revision

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.

Creation

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

Usage is identical to the standard limiter, but requires a key.

String ipAddress = request.getRemoteAddr();

if (limiter.tryAcquire(ipAddress).granted()) {
    // allow
} else {
    // deny
}

Scheduled Maintenance

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.

  1. Enable maintenance in your spec:
    .maintenanceEnabled(true)
    .maintenancePeriod(Duration.ofSeconds(30))
  2. 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.

Clone this wiki locally