Circuit breaker pattern
Circuit breaker pattern
Circuit Breaker Pattern là một mẫu thiết kế giúp bảo vệ hệ thống khỏi lỗi lan truyền khi một dịch vụ gặp sự cố hoặc mất quá nhiều thời gian phản hồi. Hiểu nôm na thì nó hoạt động giống như một công tắc điện/cầu giao điện đứng giữa các service.
Cơ chế hoạt động
Lấy ví dụ sau để giải thích cơ chế, ví dụ có 2 service, service A gọi đến service B. Khi áp dụng circuit breaker, service A sẽ không trực tiếp gọi và chờ đợi phản hồi của service B, thay vào đó nó sẽ ủy quyền cho circuit breaker (gọi sang service B bới một thread mới được quản lý bởi thread pool). Nếu số lần gọi sang service B thất bại quá số lần được cấu hình trong một khoảng thời gian quy định thì circuit breaker sẽ ngắt luôn việc gọi sang service B. Qua đó service A có thể giải phóng tài nguyên, thực hiện phản hồi cho client hoặc tại service A có thể thực hiện một xử lý dự phòng (fallback). Service B cũng có thêm thời gian để phục hồi do không phải chịu thêm tải request từ service A gọi sang.
Trạng thái của Circuit Breaker
1. Closed
- Trong trạng thái này, các yêu cầu của service A sẽ được gửi đến service B bình thường.
- Circuit Breaker theo dõi các cuộc gọi và ghi nhận tỷ lệ thành công và thất bại.
- Nếu tỷ lệ thất bại vượt quá một ngưỡng cấu hình (ví dụ: 50%), Circuit Breaker sẽ chuyển sang trạng thái Open.
2. Open (Mở)
- Trong trạng thái này, các yêu cầu đến service B sẽ bị từ chối và lỗi được trả về cho service A. Khi đó "cầu dao" sẽ ngắt kết nối, từ chối yêu cầu thay vì cố gắng gửi yêu cầu đến một service đang hoạt động không ổn định.
- Sau một khoảng thời gian chờ (wait duration), Circuit Breaker sẽ chuyển sang trạng thái Half-Open để kiểm tra xem dịch vụ đã hồi phục hay chưa.
3. Half-Open (Mở nửa chừng)
- Trong trạng thái này, một số lượng nhỏ các yêu cầu được phép thông qua để kiểm tra xem service B đã hồi phục hay chưa.
- Nếu các cuộc gọi này thành công, Circuit Breaker sẽ chuyển lại trạng thái Closed.
- Nếu các cuộc gọi này thất bại, Circuit Breaker sẽ chuyển lại trạng thái Open và chờ thêm một khoảng thời gian trước khi thử lại việc cho phép một số yêu cầu gọi sang service B.
Trường hợp sử dụng
Khi một dịch vụ phụ thuộc bị lỗi hoặc quá tải, nếu không có cơ chế kiểm soát, có thể gặp phải một số vấn đề:
Các request bị treo do chờ phản hồi từ service lỗi có thể làm down cả service phát lệnh (lỗi thời gian chờ quá lâu).
Các request liên tục retry, làm quá tải service bị gọi đến làm toàn bộ hệ thống sụp đổ (lỗi quá tải).
Một lỗi nhỏ ở một service có thể kéo sập cả hệ thống nhiều service khác (lỗi lan truyền).
Circuit Breaker giải quyết vấn đề:
Cải thiện hiệu suất: Ngắt sớm (fail fast) các request đến dịch vụ lỗi, tránh mất thời gian chờ đợi.
Giảm tải hệ thống: Ngăn chặn request không cần thiết đến dịch vụ đang gặp sự cố.
Tăng cường độ tin cậy: Đảm bảo hệ thống vẫn hoạt động dù một phần bị lỗi. Ví dụ trả về một phản hồi dự phòng (fallback pattern)
Nên sử dụng Circuit Breaker khi:
Hệ thống có nhiều microservices, đặc biệt là khi một service phụ thuộc vào nhiều service khác.
Có rủi ro cao về downtime: Nếu một dịch vụ bị lỗi có thể gây ảnh hưởng lớn đến toàn hệ thống.
Muốn tránh retry không cần thiết và bảo vệ tài nguyên hệ thống.
Dịch vụ có độ trễ cao và muốn nhanh chóng phát hiện lỗi thay vì chờ timeout.
Cách triển khai
1. Sử dụng Resilience4j
1.1. Thêm dependency vào Gradle
dependencies {
implementation 'io.github.resilience4j:resilience4j-spring-boot3:2.2.0'
}
1.2. Cấu hình Circuit Breaker
import io.github.resilience4j.circuitbreaker.annotation.CircuitBreaker;
import org.springframework.stereotype.Service;
import java.util.Random;
@Service
public class MyService {
private final Random random = new Random();
@CircuitBreaker(name = "myCircuitBreaker", fallbackMethod = "fallbackResponse")
public String callExternalService() {
if (random.nextBoolean()) {
throw new RuntimeException("Dịch vụ gặp lỗi!");
}
return "Dữ liệu từ dịch vụ chính";
}
public String fallbackResponse(Exception e) {
return "Dịch vụ đang gặp sự cố, vui lòng thử lại sau!";
}
}
Giải thích:
Nếu
callExternalService()
thất bại nhiều lần liên tiếp, circuit breaker sẽ chuyển trạng thái half-open và gọifallbackResponse()
.Sau một khoảng thời gian, nó sẽ kiểm tra xem service đã hoạt động lại chưa.
1.3. Cấu hình Circuit Breaker trong application.yml
resilience4j:
circuitbreaker:
instances:
myCircuitBreaker:
failureRateThreshold: 50 # Ngưỡng lỗi để mở mạch (50%)
waitDurationInOpenState: 5s # Thời gian chờ trước khi thử lại
minimumNumberOfCalls: 5 # Ít nhất 5 request để tính toán tỷ lệ lỗi
# ngoài ra còn nhiều tham số cấu hình khác
Giải thích:
Nếu hơn 50% request bị lỗi, circuit breaker sẽ "mở mạch".
Sau 5 giây, nó sẽ thử lại dịch vụ xem có hoạt động lại không.