Resilient Microservice Design With Spring Boot — Rate Limiter Pattern

Need For Resiliency:

Why Rate Limiter?

Sample Application:

Stock Service W/O Rate Limiter:

  • First I create a simple spring boot application with web dependency.
  • StockController
@RestController
public class StockController {

@Autowired
private StockService stockService;

@GetMapping("/stocks")
public List<StockPrice> getStockPrices(){
return this.stockService.getStocks();
}

}
  • StockPrice — DTO
public class StockPrice {

private String stock;
private int price;

//getters, setters, constructor

}
  • StockService → getStocks method is very time consuming call. We simulate that using hard coded sleep.
  • We were able to make 90 requests in total
  • Throughput is 2.9 request / sec

Stock Service With Rate Limiter:

  • I make below changes to implement the rate limiter pattern using Resilience library.
<dependency>
<groupId>io.github.resilience4j</groupId>
<artifactId>resilience4j-spring-boot2</artifactId>
<version>1.1.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
  • We provide the rate limit specific configuration
  • limitRereshPeriod is the interval — in our case it is 5 seconds
  • limitForPeriod is number of requests to make every 5 seconds. In our case, it should be just 1. We want to make only one call every 5 second. All other requests should not be allowed within the 5 second window
  • timeoutDuration — additional requests within the 5 seconds should be timedout immediately.
resilience4j.ratelimiter:
instances:
stockService:
limitForPeriod: 1
limitRefreshPeriod: 5s
timeoutDuration: 0s
  • getStocks method is time consuming. So we would like to limit the calls. We add @RateLimiter with the instance name we had defined in the application.yaml
  • When any additional requests arrive within the 5 second window will fail and call the fall back method.
  • Here we cache the response and return as part of fall back. Every 5 second we update our cache.
  • Throughput has increased from 2.9 requests/sec to 30.5 requests/sec
  • Average response time has dropped to 26 ms from 3 seconds.

Summary:

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Vinoth Selvaraj

Vinoth Selvaraj

Principal Software Engineer — passionate about software architectural design, microservices.