Fixed-window algorithm
The fixed-window algorithm divides time into discrete, non-overlapping windows of fixed duration. Each window has its own counter that tracks the number of requests.How it works
Window boundary calculation
Calculate the start of the current window by rounding down the current timestamp to the nearest window boundary:This ensures all requests in the same time window use the same Redis key.
Visual example
Consider a rate limit of 5 requests per 10 seconds: At the 10-second boundary, the counter resets (the old Redis key expires), and a new window begins.Redis implementation details
TheRedisRateLimiter class (redis/RedisRateLimiter.java:19) uses a carefully designed Redis key structure and operations.
Key structure
Each rate limit window is stored in Redis with a key format:Key components breakdown
Key components breakdown
- prefix: Configurable namespace (default:
ratelimiter) - resolvedKey: The key generated by your
RateLimitKeyResolver(e.g.,global:com.example.ApiController#getData) - windowStartMillis: The timestamp of the window start in milliseconds (e.g.,
1678900820000)
Redis operations
The limiter performs two Redis operations per request:The TTL is set to
window duration + 1 second as a safety buffer. This prevents edge cases where a key might be accessed after its intended expiration.Window boundary calculation
Here’s how the algorithm calculates window boundaries from the source code (redis/RedisRateLimiter.java:54-56):Example calculation
For a 60-second window at timestamp1,678,900,825,000 milliseconds:
Rate limit decision
After incrementing the counter, the limiter constructs aRateLimitDecision object (redis/RedisRateLimiter.java:61-67):
Decision fields
Whether the request should be allowed through
Milliseconds until the rate limit resets (0 if allowed, or time until window expires if denied)
Duration the client should wait before retrying (null if allowed, equals resetAfter if denied)
Duration until the current window expires and the counter resets
Performance characteristics
Time complexity
O(1) - Only two Redis operations per request (INCR + EXPIRE)
Space complexity
O(K × W) - K unique keys × W active windows. Keys auto-expire via TTL.
Network overhead
2 round trips - INCR and EXPIRE (though EXPIRE is only set once per window)
Atomicity
Strongly consistent - Redis INCR is atomic across all clients
Comparison with other algorithms
Fixed window vs sliding window
Fixed window vs sliding window
Fixed window (this library):
- Pros: Simple, efficient, low memory
- Cons: Can allow 2× limit at boundaries
- Pros: Smoother rate limiting, no boundary burst
- Cons: More complex, higher memory usage (requires storing timestamps)
Fixed window vs token bucket
Fixed window vs token bucket
Fixed window (this library):
- Pros: Simpler to reason about, no background refill logic
- Cons: Less flexible for burst handling
- Pros: Better burst handling, allows accumulation
- Cons: Requires background token refill, more complex state
Fixed window vs leaky bucket
Fixed window vs leaky bucket
Fixed window (this library):
- Pros: No queue management, instant feedback
- Cons: No request smoothing
- Pros: Smooths traffic, predictable output rate
- Cons: Requires queue, delayed feedback to clients
The fixed-window algorithm is ideal for most API rate limiting use cases where simplicity and performance are priorities. If you need to prevent boundary bursts, consider implementing a sliding window algorithm as a custom
RateLimiter implementation.Error handling
When Redis operations fail, the limiter’s behavior depends on thefailOpen configuration (redis/RedisRateLimiter.java:69-77):
Next steps
Key resolution
Learn how rate limit keys are generated from method context
Fail-open vs fail-closed
Configure fault tolerance behavior