Rate Limiting in Java: From Theory to Practical Implementation
Rate Limiting is one of the key mechanisms for protecting and managing load in modern distributed systems. In Java, this problem is solved both at the level of built-in tools and with the help of specialized libraries. In this article, we will analyze the main algorithms, popular libraries, and provide working code examples.
Why is Rate Limiting needed?
Rate Limiting allows you to:
- Protect the API from abuse (DDoS, password brute-forcing)
- Distribute load evenly on the backend
- Comply with Service Level Agreements (SLA)
- Prevent exceeding quotas of external services
Basic Rate Limiting Algorithms
Before choosing a library, it is important to understand the underlying algorithms:
1. Token Bucket (Bucket4j, Guava)
A classic algorithm. Tokens are added to a "bucket" at a certain rate. Each request takes one or more tokens. If there are no tokens, the request is rejected.
// Pseudocode exampleclass TokenBucket { private int tokens; private long lastRefillTime; private final int capacity; private final double refillRate; // tokens per second
synchronized boolean tryConsume() { refill(); if (tokens > 0) { tokens--; return true; } return false; }}2. Sliding Window Log
Stores timestamps of recent requests. On each new request, it removes timestamps older than the window and checks if the limit has been exceeded. Accurate, but requires memory to store timestamps.
3. Fixed Window Counter
A simple counter for a fixed interval (e.g., 100 requests per minute). Resets every minute. Vulnerable to "burst" loads at window boundaries.
Popular Java Libraries for Rate Limiting
1. Bucket4j
Bucket4j is a mature library that fully implements the Token Bucket algorithm. Supports distributed scenarios via Redis, Hazelcast, JCache. Has a Java 8+ API.
Installation (Maven):
<dependency> <groupId>com.github.vladimir-bukhtoyarov</groupId> <artifactId>bucket4j-core</artifactId> <version>8.7.0</version></dependency>Usage example:
import io.github.bucket4j.*;import java.time.Duration;
public class Bucket4jExample { public static void main(String[] args) { // Create a bucket: 10 tokens, refill 1 token per second Bandwidth limit = Bandwidth.simple(10, Duration.ofSeconds(1)); Bucket bucket = Bucket4j.builder().addLimit(limit).build();
for (int i = 0; i < 15; i++) { if (bucket.tryConsume(1)) { System.out.println("Request #" + i + " executed"); } else { System.out.println("Request #" + i + " rejected (limit exceeded)"); } } }}2. Resilience4j RateLimiter
Part of a popular fault-tolerance framework. Works based on SemaphoreBasedRateLimiter or AtomicRateLimiter. Easily integrates with Spring Boot.
Configuration example:
import io.github.resilience4j.ratelimiter.*;import java.time.Duration;
public class Resilience4jExample { public static void main(String[] args) { RateLimiterConfig config = RateLimiterConfig.custom() .limitForPeriod(5) // 5 requests .limitRefreshPeriod(Duration.ofSeconds(1)) // every second .timeoutDuration(Duration.ofMillis(100)) .build();
RateLimiter rateLimiter = RateLimiter.of("myService", config);
for (int i = 0; i < 8; i++) { Runnable task = R Also in library
JSON Processing in C++: Libraries, Parsing and Data Serialization
PSR-3 Logger Interface for PHP: Complete Guide with Examples
PHP Task Scheduler: Complete Guide to Cron Jobs and Task Scheduler