1. Circuit Breaker Pattern là gì ?
Trong kiến trúc microservices, Circuit Breaker là một mẫu thiết kế được sử dụng để xử lý lỗi có thể xảy ra khi gọi remote service. Mục đích của Circuit Breaker là ngăn chặn một loạt lỗi trong hệ thống phân tán bằng cách cung cấp cơ chế dự phòng khi dịch vụ không khả dụng hoặc gặp sự cố.
– Trạng thái Closed
Ban đầu Circuit Breaker ở trạng thái Closed, cho phép gọi remote service diễn ra bình thường. Ở trạng thái này Circuit Breaker sẽ giám sát hoạt động gọi remote. Nếu gọi thành công nó sẽ reset lại bộ đếm lỗi ngược lại nếu không thành công nó sẽ tăng số lần lỗi.
– Trạng thái Open
Nếu số lần lỗi trong một khoảng thời gian được chỉ định vượt quá ngưỡng được xác định trước, Circuit Breaker sẽ chuyển sang trạng thái Open. Ở trạng thái Open, các cuộc gọi tiếp theo đến remote service sẽ bị chặn và Circuit Breaker sẽ ngay lập tức trả về phản hồi dự phòng (fallBack) được xác định trước mà không cố gắng gọi remote service. Điều này ngăn các cuộc gọi bổ sung làm quá tải dịch vụ đang lỗi và cho phép microservice có thời gian phục hồi.
– Trạng thái Half-Open
Sau một khoảng thời gian nhất định, Circuit Breaker sẽ chuyển sang trạng thái Half-Open, cho phép một số lượng cuộc gọi giới hạn đến remote service để kiểm tra xem nó đã phục hồi chưa. Nếu các cuộc gọi thử nghiệm này thành công, Circuit Breaker sẽ chuyển trở lại trạng thái Closed, cho phép tiếp tục hoạt động bình thường. Nếu các cuộc gọi thử nghiệm tiếp tục không thành công, Circuit Breaker vẫn ở trạng thái mở và quá trình lặp lại.
– Tóm lại:
Bằng cách sử dụng Circuit Breaker Pattern , các microservice có thể xử lý lỗi trong các hệ thống phân tán một cách nhẹ nhàng, cải thiện khả năng chịu lỗi và ngăn ngừa lỗi lan truyền. Việc triển khai Circuit Breaker đòi hỏi phải cấu hình cẩn thận các ngưỡng, thời gian chờ và cơ chế dự phòng để đảm bảo hiệu suất và khả năng phục hồi tối ưu khi gặp lỗi. Ngoài ra còn có các thư viện và framework có sẵn trong nhiều ngôn ngữ lập trình khác nhau cung cấp các triển khai của Circuit Breaker Pattern, đơn giản hóa việc tích hợp vào kiến trúc microservice.
2. Resilience4j là gì?
Resilience4j là một thư viện nhẹ, chịu lỗi lấy cảm hứng từ Netflix Hystrix nhưng có cách tiếp cận hiện đại và chức năng hơn.
Thư viện này tích hợp tốt với Spring Boot và cung cấp các tính năng như circuit breakers, rate limiters, retry mechanisms, and bulkheads
Resilience4j cung cấp các chú thích như @CircuitBreaker để kích hoạt Circuit Breaker và cho phép cấu hình chi tiết hơn.
– Điểm mạnh:
Cung cấp một cách tiếp cận hiện đại và chức năng cho các mẫu phục hồi.
Cung cấp một bộ tính năng phong phú bao gồm bộ ngắt mạch(circuit breakers), bộ giới hạn tốc độ(rate limiters), cơ chế thử lại(retry mechanisms) và vách ngăn(bulkheads).
Tích hợp tốt với Spring Boot và hỗ trợ lập trình phản ứng.
– Điểm yếu:
Yêu cầu hiểu sâu hơn về các khái niệm lập trình chức năng so với các thư viện khác.
Hỗ trợ cộng đồng hạn chế so với các thư viện đã được thiết lập lâu đời hơn như Hystrix.
3. Áp dung Circuit Breakers trong Microservice
Bối cảnh: Authentication service gọi Account service thông qua RestTemplate
3.1 Authentication service
– Thêm dependency vào pom.xml
<dependency> <groupId>io.github.resilience4j</groupId> <artifactId>resilience4j-spring-boot3</artifactId> <version>2.0.2</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId> </dependency>
– Cấu hình Circuit Breaker tại application.yml
management: # cho phép hiển thị thông tin sức khoẻ của service endpoints: web: exposure: include: '*' endpoint: health: show-details: always health: circuitbreakers: enabled: true ratelimiters: enabled: true resilience4j.circuitbreaker: # This specifies the configuration for the circuit breaker module of Resilience4j. configs: # This defines the different circuit breaker configurations. In this case, there is a single configuration named "default". default: registerHealthIndicator: true # This parameter determines whether to register a health indicator for the circuit breaker. It allows monitoring the circuit breaker's health status. slidingWindowSize: 10 # This sets the size of the sliding window used by the circuit breaker to track the success and failure rates of calls. minimumNumberOfCalls: 5 # This specifies the minimum number of calls required within the sliding window before the circuit breaker can calculate the success or failure rate. permittedNumberOfCallsInHalfOpenState: 3 # This sets the maximum number of calls allowed when the circuit breaker is in the half-open state. If this limit is exceeded, the circuit breaker transitions back to the open state. automaticTransitionFromOpenToHalfOpenEnabled: true # This parameter enables or disables automatic transition from the open state to the half-open state when the wait duration in the open state has passed. waitDurationInOpenState: 5s # This determines the duration that the circuit breaker remains in the open state before transitioning to the half-open state. In this case, it is set to 5 seconds. failureRateThreshold: 50 # This sets the failure rate threshold in percentage. If the failure rate exceeds this threshold within the sliding window, the circuit breaker transitions to the open state. eventConsumerBufferSize: 10 # This parameter determines the size of the buffer used by the event consumer for tracking circuit breaker events.
– Cấu hình RestTemplate tại AppConfig.class
@Configuration public class AppConfig { @Bean public RestTemplate restTemplate() { return new RestTemplate(); } }
– Áp dụng Circuit Breakers Pattern để gọi Account service tại WelcomeController.class
@RestController public class WelcomeController { private final RestTemplate restTemplate; public WelcomeController(RestTemplate restTemplate) { this.restTemplate = restTemplate; } @CircuitBreaker(name = "accountServiceCircuitBreaker", fallbackMethod = "errorMessage") @GetMapping("/call-account-service") public String callAccountService() { String response = restTemplate.getForObject("http://localhost:8082/account/service-name", String.class); return "
<h1>Hello from the ” + response + “!</h1>
“; } /** * Fall back method * @param throwable * @return string */ public String errorMessage(Throwable throwable) { return “Service unavailable, please try again!”; } }
– Health Check http://localhost:8081/actuator/health
{ "status": "UP", "components": { "circuitBreakers": { "status": "UP", "details": { "accountServiceCircuitBreaker": { "status": "UP", "details": { "failureRate": "-1.0%", "failureRateThreshold": "50.0%", "slowCallRate": "-1.0%", "slowCallRateThreshold": "100.0%", "bufferedCalls": 1, "slowCalls": 0, "slowFailedCalls": 0, "failedCalls": 1, "notPermittedCalls": 0, "state": "CLOSED" } } } }, "clientConfigServer": { "status": "UNKNOWN", "details": { "error": "no property sources located" } }, "discoveryComposite": { "status": "UP", "components": { "discoveryClient": { "status": "UP", "details": { "services": [ "api-gateway", "authentication-service" ] } }, "eureka": { "description": "Remote status from Eureka server", "status": "UP", "details": { "applications": { "API-GATEWAY": 1, "AUTHENTICATION-SERVICE": 1 } } } } }, "diskSpace": { "status": "UP", "details": { "total": 494384795648, "free": 369594998784, "threshold": 10485760, "path": "/Users/quoctay/Workspace/training/MicroserviceFullSeries/source/authentication-service/.", "exists": true } }, "ping": { "status": "UP" }, "rateLimiters": { "status": "UNKNOWN" }, "refreshScope": { "status": "UP" } } }
3.2 Account service
Tạo api sau: http://localhost:8082/account/service-name
4. Test Circuit Breakers Pattern với Resilience4j
Để test fallbackMethod chúng ta cần start authentication-service và stop account-service
$ curl --location 'http://localhost:8081/auth/call-account-service'
– Kết quả:
Service unavailable, please try again!