As multiple independent services interact with one another in a microservices design, maintaining system resilience becomes important. Managing failures that could arise from a service outage or high latency is one typical problem. A design pattern called the circuit breaker pattern solves this problem by offering a fallback and preventing a cascading failure. In this blog, we’ll look at the Circuit Breaker pattern of Spring Boot apps.
Understanding the Circuit Breaker Pattern:
An electrical circuit breaker and the circuit breaker pattern play a similar role. It keeps an eye out for malfunctions and, when reaching a predetermined threshold, opens the circuit to stop more calls to the malfunctioning service. This enables the system to fail gracefully and restart when the malfunctioning service is back up and running.
Spring Boot Implementation:
Maven
<!-- Add Resilience4j dependency in pom.xml --><dependency><groupId>io.github.resilience4j</groupId><artifactId>resilience4j-spring-boot2</artifactId></dependency><!-- Add Resilience4j dependency in pom.xml --> <dependency> <groupId>io.github.resilience4j</groupId> <artifactId>resilience4j-spring-boot2</artifactId> </dependency><!-- Add Resilience4j dependency in pom.xml --> <dependency> <groupId>io.github.resilience4j</groupId> <artifactId>resilience4j-spring-boot2</artifactId> </dependency>
Enter fullscreen mode Exit fullscreen mode
Gradle
<!-- Add Resilience4j dependency in build.gradle -->dependencies {implementation 'io.github.resilience4j:resilience4j-spring-boot2:1.7.1'}<!-- Add Resilience4j dependency in build.gradle --> dependencies { implementation 'io.github.resilience4j:resilience4j-spring-boot2:1.7.1' }<!-- Add Resilience4j dependency in build.gradle --> dependencies { implementation 'io.github.resilience4j:resilience4j-spring-boot2:1.7.1' }
Enter fullscreen mode Exit fullscreen mode
Let’s now build a basic Spring Boot application that breaks circuits using Resilience4j.
1. Create a Spring Boot Application:
import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.SpringBootApplication;@SpringBootApplicationpublic class CircuitBreakerTestApplication {public static void main(String[] args) {SpringApplication.run(CircuitBreakerTestApplication.class, args);}}import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class CircuitBreakerTestApplication { public static void main(String[] args) { SpringApplication.run(CircuitBreakerTestApplication.class, args); } }import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class CircuitBreakerTestApplication { public static void main(String[] args) { SpringApplication.run(CircuitBreakerTestApplication.class, args); } }
Enter fullscreen mode Exit fullscreen mode
2. Create a Service with Circuit Breaker:
Create and name the service class as TestService, which will have a method that we want to protect with a circuit breaker:
import org.springframework.stereotype.Service;import io.github.resilience4j.circuitbreaker.annotation.CircuitBreaker;@Servicepublic class TestService {@CircuitBreaker(name = "testService", fallbackMethod = "fallbackMethod")public String invokeExternalService() {// Here you can simulate a call to an external service// In a real-world scenario, this could be an HTTP call, database query, etc.if (Math.random() > 0.5) {throw new RuntimeException("Service failure");}return "External service response";}public String fallbackMethod(Exception e) {return "Fallback response";}}import org.springframework.stereotype.Service; import io.github.resilience4j.circuitbreaker.annotation.CircuitBreaker; @Service public class TestService { @CircuitBreaker(name = "testService", fallbackMethod = "fallbackMethod") public String invokeExternalService() { // Here you can simulate a call to an external service // In a real-world scenario, this could be an HTTP call, database query, etc. if (Math.random() > 0.5) { throw new RuntimeException("Service failure"); } return "External service response"; } public String fallbackMethod(Exception e) { return "Fallback response"; } }import org.springframework.stereotype.Service; import io.github.resilience4j.circuitbreaker.annotation.CircuitBreaker; @Service public class TestService { @CircuitBreaker(name = "testService", fallbackMethod = "fallbackMethod") public String invokeExternalService() { // Here you can simulate a call to an external service // In a real-world scenario, this could be an HTTP call, database query, etc. if (Math.random() > 0.5) { throw new RuntimeException("Service failure"); } return "External service response"; } public String fallbackMethod(Exception e) { return "Fallback response"; } }
Enter fullscreen mode Exit fullscreen mode
In the CircuitBreaker annotation, name is the identifier for the circuit breaker, and fallbackMethod is the method that is to be called when the circuit is open.
3. Write a controller class to Invoke the TestService:
import org.springframework.beans.factory.annotation.Autowired;import org.springframework.web.bind.annotation.GetMapping;import org.springframework.web.bind.annotation.RestController;@RestControllerpublic class TestController {@Autowiredprivate TestService testService;@GetMapping("/invokeService")public String invokeService() {return testService.invokeExternalService();}}import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; @RestController public class TestController { @Autowired private TestService testService; @GetMapping("/invokeService") public String invokeService() { return testService.invokeExternalService(); } }import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; @RestController public class TestController { @Autowired private TestService testService; @GetMapping("/invokeService") public String invokeService() { return testService.invokeExternalService(); } }
Enter fullscreen mode Exit fullscreen mode
4. Enable Resilience4j Configuration
You can add the below properties to your application.properties or application.yml file to configure Resilience4j:
resilience4j.circuitbreaker.configs.default.failureRateThreshold=50resilience4j.circuitbreaker.configs.default.slidingWindowSize=5resilience4j.circuitbreaker.configs.default.failureRateThreshold=50 resilience4j.circuitbreaker.configs.default.slidingWindowSize=5resilience4j.circuitbreaker.configs.default.failureRateThreshold=50 resilience4j.circuitbreaker.configs.default.slidingWindowSize=5
Enter fullscreen mode Exit fullscreen mode
5: Monitor Circuit Breaker State (Not a must)
In order to monitor the state of the circuit breaker, you can also add the following dependencies for Micrometer and Prometheus:
Maven:
<dependency><groupId>io.micrometer</groupId><artifactId>micrometer-registry-prometheus</artifactId></dependency><dependency> <groupId>io.micrometer</groupId> <artifactId>micrometer-registry-prometheus</artifactId> </dependency><dependency> <groupId>io.micrometer</groupId> <artifactId>micrometer-registry-prometheus</artifactId> </dependency>
Enter fullscreen mode Exit fullscreen mode
Gradle:
implementation 'io.micrometer:micrometer-registry-prometheus'implementation 'io.micrometer:micrometer-registry-prometheus'implementation 'io.micrometer:micrometer-registry-prometheus'
Enter fullscreen mode Exit fullscreen mode
Now Resilience4j Circuit Breaker dashboard can be accessed at http://localhost:8080/actuator/circuitbreakers.
6: Test Circuit Breaker
Utilize the /api/invokeService endpoint to submit requests while running your Spring Boot application. Change the Math.random() condition in the callExternalService method to simulate failures.
Observe how the state of the circuit breaker dashboard varies according to the success or failure of service calls.
Conclusion
The above example shows how to set up Resilience4j’s Circuit Breaker in a Spring Boot application in a basic manner. Depending on your unique use case and the interactions with external services, adjustments can be made as required.
References
https://spring.io/projects/spring-cloud-circuitbreaker
https://www.baeldung.com/spring-cloud-circuit-breaker
Github
https://github.com/tharindu1998/springboot-circuitbraker-example
原文链接:Understanding Circuit Breaker Pattern in Spring Boot for Resilient Microservices
暂无评论内容