devto 2026-06-04 원문 보기 ↗
Published 2026-06-04 by Shubham Bhati — Backend Engineer (Java 17, Spring Boot, Microservices).
We've all been there - our Spring Boot REST API is performing well, handling a decent amount of traffic, when suddenly we're hit with a massive influx of requests, causing our servers to slow down or even crash. This is where spring boot rate limiting comes into play, helping us protect our APIs from abuse and ensuring a smooth user experience. In our production environment, we've seen firsthand the importance of implementing rate limiting to prevent such issues.
Rate limiting is a technique used to control the number of requests an API receives within a certain time frame. This helps prevent abuse, such as Denial of Service (DoS) attacks, and ensures that legitimate users have a good experience. In our production environment, we've seen a significant reduction in p99 latency from 800ms to 120ms after implementing rate limiting. We're using Java 21 and Spring Boot 3.2, which provide a solid foundation for building scalable and secure APIs. For more information on rate limiting, you can check out the Spring documentation.
Bucket4j is a popular Java library for rate limiting that provides a simple and efficient way to implement token bucket algorithms. We chose Bucket4j because of its ease of use and flexibility. Here's an example of how we're using Bucket4j in our Spring Boot application:
import io.github.bucket4j.Bucket;
import io.github.bucket4j.Bucket4j;
import io.github.bucket4j.ConsumptionProbe;
import io.github.bucket4j.Refill;
import io.github.bucket4j.TokenBucket;
@Configuration
public class RateLimitingConfig {
@Bean
public Bucket tokenBucket() {
Refill refill = Refill.intervally(10, TimeUnit.SECONDS);
return Bucket4j.builder().withMax(100).withRefill(refill).build();
}
}
This configuration creates a token bucket that refills at a rate of 10 tokens per second, with a maximum capacity of 100 tokens.
We're using Redis as our distributed cache to store rate limiting metrics. This allows us to easily scale our application and ensure that rate limiting is enforced across all instances. To configure Redis, we're using the Spring Data Redis library. Here's an example of how we're configuring Redis:
@Configuration
public class RedisConfig {
@Bean
public RedisConnectionFactory redisConnectionFactory() {
RedisStandaloneConfiguration config = new RedisStandaloneConfiguration("localhost", 6379);
return new LettuceConnectionFactory(config);
}
}
This configuration sets up a Redis connection factory that connects to a local Redis instance on port 6379.
To implement rate limiting in our Spring Boot application, we're using a combination of Bucket4j and Redis. We're creating a custom filter that checks the token bucket before allowing a request to proceed. If the token bucket is empty, the request is blocked. Here's an example of how we're implementing the filter:
@Component
public class RateLimitingFilter implements Filter {
@Autowired
private Bucket tokenBucket;
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
ConsumptionProbe probe = tokenBucket.tryConsumeAndReturnRemaining(1);
if (probe.isConsumed()) {
chain.doFilter(request, response);
} else {
HttpServletResponse httpResponse = (HttpServletResponse) response;
httpResponse.setStatus(HttpStatus.TOO_MANY_REQUESTS.value());
httpResponse.getWriter().write("Rate limit exceeded");
}
}
}
This filter checks the token bucket before allowing a request to proceed. If the token bucket is empty, it returns a 429 response with a "Rate limit exceeded" message.
To monitor and analyze rate limiting metrics, we're using a combination of Redis and Prometheus. We're storing rate limiting metrics in Redis and then using Prometheus to scrape the metrics and display them in a dashboard. Here's an example of how we're storing rate limiting metrics in Redis:
public class RateLimitingMetrics {
@Autowired
private RedisTemplate<String, String> redisTemplate;
public void incrementRequestCount() {
redisTemplate.opsForValue().increment("request_count");
}
public void incrementBlockedRequestCount() {
redisTemplate.opsForValue().increment("blocked_request_count");
}
}
This code increments the request count and blocked request count metrics in Redis.
Here are some common mistakes to avoid when implementing rate limiting:
Rate limiting and API throttling are both techniques used to control the number of requests an API receives, but they serve different purposes. Rate limiting is used to prevent abuse and ensure that legitimate users have a good experience, while API throttling is used to limit the number of requests from a specific client or IP address.
To configure Bucket4j for rate limiting, you need to create a token bucket and specify the refill rate and maximum capacity. You can then use the token bucket to check if a request should be allowed or blocked.
The best way to monitor and analyze rate limiting metrics is to use a combination of Redis and Prometheus. You can store rate limiting metrics in Redis and then use Prometheus to scrape the metrics and display them in a dashboard.
Yes, you can use rate limiting with other caching solutions, such as Apache Ignite. However, Redis is a popular choice for rate limiting due to its ease of use and flexibility.
In conclusion, implementing rate limiting in Spring Boot using Bucket4j and Redis is a effective way to prevent abuse and ensure that legitimate users have a good experience. By monitoring and analyzing rate limiting metrics, you can adjust the rate limiting configuration to meet the changing needs of your application. For more information on rate limiting, you can check out the Baeldung tutorial on api throttling.
Written by **Shubham Bhati* — Backend Engineer at AlignBits LLC, specializing in Java 17, Spring Boot, microservices, and AI integration. Connect on LinkedIn, GitHub, or read more at shubh2-0.github.io.*