[JAVA] Rate-Limiting using RateLimiter of Resilience4j

https://github.com/resilience4j/resilience4j

resilience4j will be a prominent implementation of Circuit Breaker, primarily for Java. Rate-Limiting related features also exist.

https://github.com/resilience4j/resilience4j#ratelimiter

In the following, verification is performed based on the following sample program.

https://github.com/resilience4j/resilience4j-spring-boot2-demo

Configuration build.gradle

When linking with Spring Boot, use ʻio.github.resilience4j: resilience4j-spring-boot2`.

dependencies {
        compile('org.springframework.boot:spring-boot-starter-webflux')
        compile('org.springframework.boot:spring-boot-starter-actuator')
        compile('org.springframework.boot:spring-boot-starter-aop')

        compile("io.github.resilience4j:resilience4j-spring-boot2:${resilience4jVersion}") // <-

application.yml

resilience4j.ratelimiter:
    configs:
        default:
            registerHealthIndicator: false
            limitForPeriod: 3
            limitRefreshPeriod: 2s
            timeoutDuration: 0
            eventConsumerBufferSize: 100
    instances:
        backendA:
            baseConfig: default
        backendB:
            limitForPeriod: 6
            limitRefreshPeriod: 500ms
            timeoutDuration: 3s

With limitForPeriod: 3 and limitRefreshPeriod: 2s, Rate-Limitting is performed if there are more than 3 accesses within 2 seconds.

Java Set @RateLimiter annotation in the process to set Rate-Limitting.

    @Override
    @RateLimiter(name = BACKEND_A) // <--
    @CircuitBreaker(name = BACKEND_A)
    @Bulkhead(name = BACKEND_A)
    @Retry(name = BACKEND_A)
    public String success() {
        return "Hello World from backend A";
    }

Running With this setting, a 500 error will be returned if you access more than 3 times in 2 seconds.

Normal time (200)

< HTTP/1.1 200 OK
< Content-Type: text/plain;charset=UTF-8
< Content-Length: 26
< 
* Connection #0 to host localhost left intact
Hello World from backend A

At Rate-Limit (500)

< HTTP/1.1 500 Internal Server Error
< Content-Type: application/json
< Content-Length: 235
< 
{
  "timestamp" : "2020-05-05T09:23:13.530+0000",
  "path" : "/backendA/success",
  "status" : 500,
  "error" : "Internal Server Error",
  "message" : "RateLimiter 'backendA' does not permit further calls",
  "requestId" : "b372ed49"
}

Internally, a RuntimeException called RequestNotPermitted occurs, so it is necessary to perform appropriate error handling and HTTP StatusCode return processing in the Controller layer.

Monitoring You can get the setting contents related to Rate-Limit with / actuator / ratelimiters.

{
  "rateLimiters" : [ "backendA", "backendB" ]
}

Conclusion

With resilience4j and resilience4j-spring-boot2, it's fairly easy to add Rate-Limiting functionality to your existing Spring Boot applications.

The difference from bucket4j is that URL Path and rate-Limiting processing for each user are not supported by default.

If you want to apply Rate-Limiting processing to the entire system in earnest, it is preferable to introduce API Gateway middleware using Ambassador Pattern or Side-Car Pattern.

Recommended Posts

Rate-Limiting using RateLimiter of Resilience4j
Rate-Limiting using guava's RateLimiter
Example of using vue.config.js
Summary of using FragmentArgs
Summary of using DBFlow
Example of params using where
Summary of using Butter Knife
Example of using abstract class
Enumeration of combination patterns using List
Development of Flink using DataStream API
Validation of log messages using mockito
Handling of time zones using Java
Acquisition of location information using FusedLocationProviderClient
[Kotlin] Example of processing using Enum
Summary of object-oriented programming using Java
I tried using GoogleHttpClient of Java