LoginSignup
2
2

More than 5 years have passed since last update.

Spring Boot + Resilience4j で CircuitBreaker と RateLimiter を試す(続き)

Posted at

前回まとめきれていなかった、イベントとモニタリングについて書いていきます。

前回の記事はこちら。
Spring Boot + Resilience4j で CircuitBreaker と RateLimiter を試す

環境

  • JDK 8
  • Spring Boot 2.1.2.RELEASE
  • Resilience4j 0.13.2

CircuitBreaker

イベント

CircuitBreaker は以下のイベントを発行します。

イベント 内容
Success 処理が成功したとき
Error 処理が失敗したとき
StateTransition Circuit の状態が遷移したとき
Reset CircuitBreaker の状態をリセットしたとき
IgnoreError 無視すると設定した例外が発生したとき
CallNotPermitted Circuit が Open 状態でアクセスが遮断されたとき

これらのイベントに対して処理を行う場合には、以下のように設定できます。

@Configuration
@Slf4j
public class CircuitBreakerConfiguration {

    private final CircuitBreakerRegistry circuitBreakerRegistry;

    public CircuitBreakerConfiguration(CircuitBreakerRegistry circuitBreakerRegistry) {
        this.circuitBreakerRegistry = circuitBreakerRegistry;
    }

    @PostConstruct
    public void eventSetting() {
        circuitBreakerRegistry.getAllCircuitBreakers().forEach(circuitBreaker -> {
            circuitBreaker.getEventPublisher().onSuccess(e -> log.info("SUCESS!!!!!"))
                    .onError(e -> log.error("ERROR!!!!!"))
                    .onStateTransition(e -> log.info("{} to {}", e.getStateTransition().getFromState(),
                            e.getStateTransition().getToState()))
                    .onCallNotPermitted(e -> log.warn("Not Permitted!!!!!"))
                    .onIgnoredError(e -> log.info("Ignored!!!!!")).onReset(e -> log.info("Reset!!!!"));
        });
    }
}

CircuitBreaker から getEventPublisherで取得したオブジェクトに対して、on〜メソッドで処理を設定できます。
また、onEventメソッドを利用すれば、すべてのイベントに対して処理を設定できます。

モニタリング

Spring Boot Actuator で CircuitBreaker の情報を取得することができます。

Endpoint

circuitbreakersという Endpoint にアクセスすると、登録されている CircuitBreaker の名称を取得できます。

$ curl http://localhost:8080/actuator/circuitbreakers
{"circuitBreakers":["circuitA","circuitB"]}

circuitbreaker-eventsという Endpoint にアクセスすると、各 CircuitBreaker が発行したイベントを一覧で取得できます。

$ curl http://localhost:18080/actuator/circuitbreaker-events
{"circuitBreakerEvents":[{"circuitBreakerName":"circuitA","type":"ERROR","creationTime":"2019-01-24T10:02:21.265+09:00[Asia/Tokyo]","errorMessage":"java.lang.RuntimeException","durationInMs":4},{"circuitBreakerName":"circuitA","type":"SUCCESS","creationTime":"2019-01-24T10:02:40.239+09:00[Asia/Tokyo]","durationInMs":0},{"circuitBreakerName":"circuitA","type":"SUCCESS","creationTime":"2019-01-24T10:02:41.599+09:00[Asia/Tokyo]","durationInMs":0},{"circuitBreakerName":"circuitA","type":"ERROR","creationTime":"2019-01-24T10:02:42.754+09:00[Asia/Tokyo]","errorMessage":"java.lang.RuntimeException","durationInMs":0},{"circuitBreakerName":"circuitA","type":"ERROR","creationTime":"2019-01-24T10:02:43.860+09:00[Asia/Tokyo]","errorMessage":"java.lang.RuntimeException","durationInMs":0},{"circuitBreakerName":"circuitA","type":"STATE_TRANSITION","creationTime":"2019-01-24T10:02:43.867+09:00[Asia/Tokyo]","stateTransition":"CLOSED_TO_OPEN"},{"circuitBreakerName":"circuitA","type":"NOT_PERMITTED","creationTime":"2019-01-24T10:02:44.596+09:00[Asia/Tokyo]"},{"circuitBreakerName":"circuitA","type":"STATE_TRANSITION","creationTime":"2019-01-24T10:03:17.660+09:00[Asia/Tokyo]","stateTransition":"OPEN_TO_HALF_OPEN"},{"circuitBreakerName":"circuitA","type":"SUCCESS","creationTime":"2019-01-24T10:03:17.661+09:00[Asia/Tokyo]","durationInMs":0}]}

CircuitBreaker の名称と、イベントによって絞り込むことも可能です。
CircuitBrekaer ごとに保存されるイベントの数はデフォルトでは 100 件で、application.ymlで値を設定することができます。

resilience4j:
  circuitbreaker:
    backends:
      circuitA:
        event-consumer-buffer-size: 1000

Health Indicator

各 CircuitBreaker の状態を取得することもできます。
Health Indicator は{CircuitBreakerの名称}+"CircuitBreaker" という名前で登録されているので、以下のようにすれば状態を取得できます。

$ curl http://localhost:8080/actuator/health/circuitACircuitBreaker
{"status":"UP","details":{"failureRate":"-1.0%","failureRateThreshold":"50.0%","maxBufferedCalls":5,"bufferedCalls":2,"failedCalls":0,"notPermittedCalls":0}}

status は Circuit の状態によって決まり、Closed 時は UP、Open の時は DOWN、それ以外の時は UNKNOWN となります。

なお、各 CircuitBreaker はバラバラに登録されているので、CircuitBreaker の情報だけまとめて取得することができなさそうです。
CompositeHealthIndicatorでまとめて登録するようになっていればいいのではないかと思わなくもない)
また、デフォルトで有効になっていますが、application.ymlで無効にすることも可能です。

resilience4j:
  circuitbreaker:
    backends:
      circuitA:
        register-health-indicator: false

RateLimiter

CircuitBreaker とほとんど似たような感じです。

イベント

RateLimiter は以下のイベントを発行します。

イベント 内容
Success 処理が実行できたとき
Failure 処理が実行できないとき(タイムアウトしたとき)

イベントに対して処理を設定する方法は CircuitBreaker のときと同様です。

@Configuration
@Slf4j
public class RateLimiterConfiguration {

    private final RateLimiterRegistry rateLimiterRegistry;

    public RateLimiterConfiguration(RateLimiterRegistry rateLimiterRegistry) {
        this.rateLimiterRegistry = rateLimiterRegistry;
    }

    @PostConstruct
    public void eventSetting() {
        rateLimiterRegistry.getAllRateLimiters().forEach(rateLimiter -> {
            rateLimiter.getEventPublisher().onSuccess(e -> log.info("SUCCESS!!!!!!"))
                    .onFailure(e -> log.error("ERROR!!!!!!!"));
        });
    }
}

モニタリング

CircuitBreaker と同じような感じですが、デフォルトの挙動が微妙に異なります。

Endpoint

ratelimitersという Endpoint にアクセスすると、登録されている RateLimiter の名称を取得できます。

$ curl http://localhost:8080/actuator/ratelimiters
{"rateLimitersNames":["limiterA","limiterB"]}

ratelimiter-eventsという Endpoint にアクセスすると、各 RateLimiter が発行したイベントを一覧で取得できますが、デフォルトでは無効です。
(アクセスできるけど何も情報が蓄積されていない。)
application.ymlで有効にすることができます。また、CircuitBreaker と同様に保存されるイベントの数を変更することもできます。(デフォルトは 100)

ratelimiter:
  limiters:
    limiterA:
      subscribe-for-events: true
      event-consumer-buffer-size: 1000
$ curl http://localhost:8080/actuator/ratelimiter-events
{"eventsList":[{"rateLimiterName":"limiterA","rateLimiterEventType":"SUCCESSFUL_ACQUIRE","rateLimiterCreationTime":"2019-01-24T11:30:26.068+09:00[Asia/Tokyo]"},{"rateLimiterName":"limiterA","rateLimiterEvenall
tType":"FAILED_ACQUIRE","rateLimiterCreationTime":"2019-01-24T11:30:27.798+09:00[Asia/Tokyo]"}]}

Health Indicator

各 RateLimiter の状態を取得することができます。
Health Indicator は{RateLimiterの名称}+"RateLimiter" という名前で登録されているので、以下のようにすれば状態を取得できますが、デフォルトでは無効です。

$ curl http://localhost:8080/actuator/health/limiterARateLimiter
{"status":"UP","details":{"availablePermissions":1,"numberOfWaitingThreads":0}}

application.ymlで有効にすることができます。

ratelimiter:
  limiters:
    limiterA:
      register-health-indicator: true

status は、アクセスしたタイミングでタイムアウトが発生する状態であれば DOWN、正常に処理が可能な状態であれば UP となります。

所感

Resilience4j と Spring Boot の連携は若干やりづらい気がしました。
すべての機能に対する AutoConfiguration が揃っていませんし、イベントの登録についても少し面倒であったり、Actuator で取得できる内容や挙動についても気になる部分があります。
ただ、Spring Cloud が Hystrix の移行先として Resilience4j を挙げているので、今後はもっと便利になっていくのだろうと期待しています。

2
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
2