In this article we will look at very simple & basic example to expose Resilience4j circuit breaker statistics i.e. metrics to JMX in the form of JMX MBean. We will use the code example from this article to expose JMX metrics.
Resilience4j integration with Micrometer
Resilience4j provides integration with Micrometer. Micrometer is a simple facade library for popular monitoring systems. Micrometer provides a way to expose its statistic over JMX which we will be using for this article.
Maven dependencies required for this example
- resilience4j-micrometer – This library integrates Resilience4j with micrometer.
- micrometer-registry-prometheus – This is a micrometer dependency.
- micrometer-registry-jmx – This library mapping of micrometer to JMX.
Circuit Breaker example with micrometer & JMX integration
In below example, you can see a micrometer meter registry created using very simple jmx configurations. Then we bind circuit breaker registry with the meter registry. For any other classes used in this example, refer the article.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 |
package com.itsallbinary.resilience4j.tutorial; import io.github.resilience4j.circuitbreaker.CircuitBreaker; import io.github.resilience4j.circuitbreaker.CircuitBreakerRegistry; import io.github.resilience4j.micrometer.tagged.TaggedCircuitBreakerMetrics; import io.micrometer.core.instrument.Clock; import io.micrometer.core.instrument.MeterRegistry; import io.micrometer.jmx.JmxMeterRegistry; public class CircuitBreakerMetricsJMX { public static void main(String[] args) { /* * Micrometer registry with basic JMX configurations. Based on the framework you * use, like Spring etc., you might use meter registry provided by that * framework. */ MeterRegistry meterRegistry = new JmxMeterRegistry(s -> null, Clock.SYSTEM); // Service client object to call service. ExternalService externalService = new ExternalService(); /* * Circuit breaker with default configurations. Below are defaults. * * DEFAULT_SLIDING_WINDOW_TYPE = SlidingWindowType.COUNT_BASED; --> State change * will happen based on count of failed calls. * * DEFAULT_RECORD_EXCEPTION_PREDICATE --> All exception recorded as failures * * DEFAULT_MINIMUM_NUMBER_OF_CALLS = 100 DEFAULT_SLIDING_WINDOW_SIZE = 100; --> * Minimum number of calls to record before decision to open. * * DEFAULT_FAILURE_RATE_THRESHOLD = 50% --> Out of recorded calls, if 50% calls * are failure, then open circuit breaker * * DEFAULT_WAIT_DURATION_IN_OPEN_STATE = 60 Seconds --> Wait this much time in * open state before moving to half open. * * DEFAULT_PERMITTED_CALLS_IN_HALF_OPEN_STATE = 10 --> COunt these many calls in * half open to decide if circuit breaker can be completely open. * * * */ CircuitBreakerRegistry circuitBreakerRegistry = CircuitBreakerRegistry.ofDefaults(); CircuitBreaker circuitBreaker = circuitBreakerRegistry.circuitBreaker("externalService"); // Bing circuit breaker registry to micrometer meter registry. TaggedCircuitBreakerMetrics.ofCircuitBreakerRegistry(circuitBreakerRegistry).bindTo(meterRegistry); for (int i = 0; i < 500; i++) { System.out.println(">> Call counter = " + (i + 1)); try { // Call service every 1 second. Thread.sleep(1000); // Decorate service call in circuit breaker String status = circuitBreaker.executeSupplier(() -> externalService.callService()); System.out.println("\t>> Call Status: " + status); } catch (Exception e) { e.printStackTrace(); System.err.flush(); } finally { // Print important metric stats to observe behavior of circuit breaker. System.out.println("\t>> Successful call count: " + circuitBreaker.getMetrics().getNumberOfSuccessfulCalls() + " | Failed call count: " + circuitBreaker.getMetrics().getNumberOfFailedCalls() + " | Failure rate %:" + circuitBreaker.getMetrics().getFailureRate() + " | State: " + circuitBreaker.getState()); } } } } |
Output of this program & runtime behavior can be referred in this article.
Lets look at the JMX Mbean exposed by this example. You can run this application & then go to jconsole from your JDK/bin. In JConsole application, select the process of above program as shown below.
Then go to MBeans tab & you will see “metrics” JMX mbean which provides lot of different statistics for circuit breaker. Below screenshot shows failure rate statistics at that moment. You can keep refreshing to get latest stats.
These are the metrics that are exposed in above example.
- resilience4jCircuitbreakerBufferedCalls.kind.failed.name.externalService
- resilience4jCircuitbreakerBufferedCalls.kind.successful.name.externalService
- resilience4jCircuitbreakerCalls.kind.failed.name.externalService
- resilience4jCircuitbreakerCalls.kind.ignored.name.externalService
- resilience4jCircuitbreakerCalls.kind.not_permitted.name.externalService
- resilience4jCircuitbreakerCalls.kind.successful.name.externalService
- resilience4jCircuitbreakerFailureRate.name.externalService
- resilience4jCircuitbreakerSlowCallRate.name.externalService
- resilience4jCircuitbreakerSlowCalls.kind.failed.name.externalService
- resilience4jCircuitbreakerSlowCalls.kind.successful.name.externalService
- resilience4jCircuitbreakerState.name.externalService.state.closed
- resilience4jCircuitbreakerState.name.externalService.state.disabled
- resilience4jCircuitbreakerState.name.externalService.state.forced_open
- resilience4jCircuitbreakerState.name.externalService.state.half_open
- resilience4jCircuitbreakerState.name.externalService.state.open