Rate Limiting in Java: Overview of Libraries and Tools
Rate limiting is a critically important mechanism for protecting web services, APIs, and microservices from overloads, DDoS attacks, and accidental abuse. In Java, there are several mature libraries implementing various algorithms: from a simple counter to complex distributed systems. In this article, we will look at three main approaches: Guava RateLimiter, Bucket4j, and Resilience4j, and discuss their applications.
1. Guava RateLimiter (Simple and Lightweight)
The Google Guava library provides the RateLimiter class, which implements the Token Bucket algorithm in a single-threaded mode. It is ideal for local use within a single JVM process.
How it works: The bucket is filled with tokens at a certain rate. Each request consumes one or more tokens. If there are not enough tokens, the thread is blocked or the request is rejected.
Example of using Guava RateLimiter:
import com.google.common.util.concurrent.RateLimiter;
public class GuavaRateLimiterExample { public static void main(String[] args) { // Create a RateLimiter for 10 requests per second RateLimiter rateLimiter = RateLimiter.create(10.0);
// Simulate incoming requests for (int i = 0; i < 20; i++) { // tryAcquire() returns true if a token is acquired if (rateLimiter.tryAcquire()) { System.out.println("Request " + i + " executed"); } else { System.out.println("Request " + i + " rejected (limit exceeded)"); } } }}Pros: Minimal dependency, simplicity, low memory consumption.
Cons: Not suitable for distributed systems (does not synchronize between instances).
2. Bucket4j (Advanced Token Bucket with Redis Support)
Bucket4j is a library implementing the Token Bucket algorithm with advanced features: support for multiple state storage providers (in-memory, Redis, Hazelcast, Infinispan), allowing its use in distributed scenarios.
Key features:
- Support for greedy and interval-based modes.
- Ability to set limits for different time windows (e.g., 100 requests per minute + 10 requests per second).
- Integration with Jakarta EE / Spring Boot via ready-made filters and annotations.
Example with in-memory storage:
import io.github.bucket4j.Bandwidth;import io.github.bucket4j.Bucket;import io.github.bucket4j.Refill;
import java.time.Duration;
public class Bucket4jExample { public static void main(String[] args) { // Limit: 5 requests per 10 seconds Bandwidth limit = Bandwidth.classic(5, Refill.intervally(5, Duration.ofSeconds(10))); Bucket bucket = Bucket.builder() .addLimit(limit) .build();
for (int i = 0; i < 10; i++) { if (bucket.tryConsume(1)) { System.out.println("Request " + i + " allowed"); } else { System.out.println("Request " + i + " blocked"); } } }}Pros: Flexible configuration, distributed support, high performance.
Cons: More dependencies than Guava.
3. Resilience4j RateLimiter (for Microservice Architecture)
Resilience4j is a fault tolerance library that includes the RateLimiter module. It is designed with