前回まとめきれていなかった、イベントとモニタリングについて書いていきます。
前回の記事はこちら。
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 を挙げているので、今後はもっと便利になっていくのだろうと期待しています。