#1
Rate limiting protects APIs from excessive traffic and abuse. A simple fixed-window rate limiter can work, but it has a weakness: requests may spike at the boundary of time windows.
A sliding window rate limiter solves this problem by tracking requests over a continuous time range instead of fixed intervals. Redis Sorted Sets make this implementation efficient and scalable.
This article explains how to build a sliding window rate limiter in Spring Boot using Redis.

1. How Sliding Window Rate Limiting Works

Instead of counting requests per fixed minute, the system stores timestamps of requests.
Example request timeline:
Time Window: 60 seconds
Requests:
10:00:01
10:00:05
10:00:20
10:00:50
When a new request arrives:
  1. Remove timestamps older than the time window.
  2. Count remaining requests.
  3. If count exceeds the limit → reject the request.

2. Using Redis Sorted Sets

Redis Sorted Sets store elements with a score.
For rate limiting:
  • Element → request ID
  • Score → timestamp
Example key:
rate_limit:user123
Structure:
rate_limit:user123
 ├── request1 : timestamp
 ├── request2 : timestamp
 └── request3 : timestamp
Redis keeps entries sorted by timestamp.

3. Creating the Rate Limiter Service

Example implementation:
@Service
public class SlidingWindowRateLimiter {

    @Autowired
    private RedisTemplate<String, String> redisTemplate;

    public boolean allowRequest(String key, int limit, long windowSeconds) {

        long now = System.currentTimeMillis();
        long windowStart = now - (windowSeconds * 1000);

        ZSetOperations<String, String> zSet = redisTemplate.opsForZSet();

        // Remove old requests
        zSet.removeRangeByScore(key, 0, windowStart);

        Long requestCount = zSet.zCard(key);

        if (requestCount != null && requestCount >= limit) {
            return false;
        }

        // Add current request
        zSet.add(key, UUID.randomUUID().toString(), now);

        redisTemplate.expire(key, Duration.ofSeconds(windowSeconds));

        return true;
    }
}
This method checks whether a request should be allowed.

4. Applying Rate Limiting in a Controller

Use the limiter inside an API endpoint.
@RestController
@RequestMapping("/api")
public class ApiController {

    @Autowired
    private SlidingWindowRateLimiter rateLimiter;

    @GetMapping("/data")
    public ResponseEntity<String> getData(HttpServletRequest request) {

        String ip = request.getRemoteAddr();
        String key = "rate_limit:" + ip;

        if (!rateLimiter.allowRequest(key, 20, 60)) {
            return ResponseEntity.status(429)
                    .body("Too many requests");
        }

        return ResponseEntity.ok("Request allowed");
    }
}
Example limit:
20 requests per 60 seconds

5. Benefits of Sliding Window Rate Limiting

Compared to fixed-window limits:
Advantages:
  • More accurate request control
  • Prevents burst traffic spikes
  • Fair request distribution
  • Works well in distributed systems

6. Using User or API Key Limits

Instead of IP addresses, use user IDs or API keys.
Example keys:
rate_limit:user:101
rate_limit:api_key:abcd1234
This is useful for SaaS platforms and public APIs.

7. Scaling Rate Limiting

Redis supports distributed rate limiting across multiple application instances.
Architecture example:
Clients
   ↓
Load Balancer
   ↓
Spring Boot Instances
   ↓
Redis Rate Limiter
All instances share the same rate limit data.

8. Monitoring Rate Limits

Track useful metrics:
  • Blocked requests
  • Top rate-limited clients
  • Request rate per endpoint
Expose metrics with Spring Boot Actuator:
management.endpoints.web.exposure.include=metrics
#ads

image quote pre code