Backend Development 6 min read

How to Implement Rate Limiting in Microservices with Resilience4j

This article explains why rate limiting is essential for resilient microservices, demonstrates a simple e‑commerce order flow, and provides step‑by‑step code examples using Resilience4j to restrict request throughput, handle overload, and automatically retry failed calls.

Java Architecture Diary
Java Architecture Diary
Java Architecture Diary
How to Implement Rate Limiting in Microservices with Resilience4j

Introduction

Microservices are essentially distributed architectures; when using a distributed system, any unpredictable issue—such as network, service, or middleware availability problems—can occur. A problem in one system may directly affect another system's usage or performance. Therefore, during system design we must ensure our own resilience while avoiding cascading failures to downstream services.

Rate Limiting Pattern

In a microservice architecture with multiple services (A, B, C, D), a service (A) may depend on another service (B), which in turn may depend on C, and so on.

The diagram below shows two services, A and B, where B performs heavy business calculations and external calls, resulting in a maximum request capacity smaller than the concurrent requests from A.

When service A receives many requests, B cannot handle the load and may crash.

Service B protects itself by rejecting requests it cannot process, ensuring normal operation.

Rate limiting restricts the number of requests processed within a specified time window, helping improve service availability.

Sample Program

Architecture Diagram

The diagram illustrates a simple e‑commerce order flow.

User logs in and browses products (inventory module)

Deduct product inventory (inventory module)

Create product order (order module)

product‑service calls order‑service to place an order.

Code Implementation

<code>├── ratelimiter-demo
   ├── order-service        # Order service (port 8070)
   └── product-service      # Product inventory service (port 8050)
</code>

Dependency note: Hystrix is outdated; this demo uses Resilience4j circuit breaker.

<code>&lt;dependency&gt;
    &lt;groupId&gt;io.github.resilience4j&lt;/groupId&gt;
    &lt;artifactId&gt;resilience4j-spring-boot2&lt;/artifactId&gt;
    &lt;version&gt;1.6.1&lt;/version&gt;
&lt;/dependency&gt;
</code>

Retry policy: at most 5 requests are allowed within a 10‑second window.

<code>resilience4j.ratelimiter:
  instances:
    createOrder:
      limitForPeriod: 5        # maximum number of calls
      limitRefreshPeriod: 10s  # time window
</code>

Consumer interface (product‑service, port 8050)

<code>/**
 * User clicks purchase
 */
@SneakyThrows
@GetMapping("/order")
public String buy() {
    // Simulate calling order service to create an order
    orderService.createOrder().get();
    return "success";
}
</code>

Remote call class wrapped with @RateLimiter

<code>/**
 * Create order
 * name: specifies the rate limiter configuration name
 * fallbackMethod: method to call when rate limit is exceeded
 */
@RateLimiter(name = "createOrder", fallbackMethod = "getError")
public CompletableFuture<String> createOrder() {
    return CompletableFuture.supplyAsync(() ->
        restTemplate.getForEntity("http://localhost:8070/createOrder", String.class).getBody()
    );
}

public CompletableFuture<String> getError(Throwable error) {
    log.warn("Order creation failed {}", error.getMessage());
    throw new RuntimeException("Order creation failed");
}
</code>

Provider service (order‑service, port 8070)

<code>@RestController
public class PayController {
    @SneakyThrows
    @GetMapping("/createOrder")
    public String createOrder() {
        return "创建订单服务";
    }
}
</code>

Running the Test

10 concurrent threads request the product service; the policy allows only 5 requests per 10 seconds.

Order service log shows the first request triggers a RateLimiter exception; the client automatically retries, causing a second call.

<code>2020-12-07 15:53:46.698  WARN 52265 --- [nio-8050-exec-6] c.example.product.service.OrderService   : 创建订单失败了 RateLimiter 'createOrder' does not permit further calls

... exception log ...
</code>

Source code: https://github.com/lltx/microservices-pattern

Reference material and some images: https://www.vinsguru.com

Backenddistributed systemsmicroservicesSpring BootRate LimitingResilience4j
Java Architecture Diary
Written by

Java Architecture Diary

Committed to sharing original, high‑quality technical articles; no fluff or promotional content.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.