Lập trình · 21/09/2026

Circuit Breaker thực chiến: Ngăn lỗi dây chuyền khi gọi dịch vụ bên ngoài

Khi một dịch vụ phụ thuộc chậm hoặc ngừng hoạt động, tiếp tục gửi request có thể làm cạn thread, connection pool và memory của chính dịch vụ gọi. Circuit Breaker ngắt tạm thời các lời gọi có khả năng thất bại, trả lỗi nhanh hoặc dùng fallback, cho dependency thời gian phục hồi và ngăn sự cố lan ra toàn hệ thống.

Circuit Breaker thực chiến: Ngăn lỗi dây chuyền khi gọi dịch vụ bên ngoài

Khi một dịch vụ phụ thuộc chậm hoặc ngừng hoạt động, tiếp tục gửi request có thể làm cạn thread, connection pool và memory của chính dịch vụ gọi. Circuit Breaker ngắt tạm thời các lời gọi có khả năng thất bại, trả lỗi nhanh hoặc dùng fallback, cho dependency thời gian phục hồi và ngăn sự cố lan ra toàn hệ thống.

Vì sao timeout và retry chưa đủ?

Timeout giới hạn thời gian của một lần gọi. Retry xử lý lỗi thoáng qua. Nhưng khi dependency hỏng kéo dài, mỗi request mới lại timeout rồi retry, nhân lượng tải đúng lúc hệ thống yếu nhất. Một request người dùng có ba lần thử và đi qua nhiều tầng có thể tạo ra hàng chục lời gọi xuống dưới.

Circuit Breaker ghi nhận kết quả trong một cửa sổ gần đây. Khi lỗi hoặc slow call vượt ngưỡng, breaker mở và từ chối ngay các lời gọi tiếp theo thay vì chờ network timeout.

Ba trạng thái cốt lõi

Trạng tháiHành viChuyển trạng thái
ClosedCho request đi qua và đo kết quảMở khi đủ mẫu và vượt ngưỡng lỗi/chậm
OpenFail fast, không gọi dependencySang Half-Open sau thời gian chờ
Half-OpenChỉ cho một số probe giới hạnĐóng khi đủ probe thành công; mở lại nếu thất bại

Half-Open phải giới hạn concurrency. Nếu toàn bộ traffic cùng thử lại ngay khi hết thời gian chờ, dependency vừa hồi phục có thể bị đánh sập lần nữa.

Đặt breaker ở đúng ranh giới

Tạo breaker theo dependency và operation có đặc điểm phục hồi tương tự, ví dụ payment-authorize tách khỏi payment-history. Không dùng một breaker toàn cục cho mọi endpoint hoặc mọi shard: lỗi ở một tài nguyên sẽ chặn cả tài nguyên đang khỏe.

Trong hệ thống nhiều instance, breaker local phản ứng nhanh và không phụ thuộc một kho trạng thái chung. Đổi lại, mỗi instance có góc nhìn riêng. Breaker phân tán có thể nhất quán hơn nhưng thêm latency và một dependency mới; chỉ dùng khi bài toán thực sự cần.

Chỉ đếm lỗi phản ánh sức khỏe dependency

  • Nên đếm: timeout, connection refused/reset, HTTP 5xx liên quan dependency, response chậm vượt SLO.
  • Thường không đếm: 400 do input sai, 401/403 do quyền người dùng, 404 nghiệp vụ hợp lệ.
  • Cần chính sách riêng: 429 nên tôn trọng Retry-After; một số 409 là conflict nghiệp vụ chứ không phải outage.

Nếu đếm mọi exception, traffic xấu từ client có thể mở breaker dù dependency hoàn toàn khỏe.

Cấu hình từ dữ liệu, không sao chép con số

window: 100 calls
minimumCalls: 20
failureRateThreshold: 50%
slowCallDuration: 800 ms
slowCallRateThreshold: 60%
openDuration: 15 s
halfOpenPermittedCalls: 5

Đây chỉ là ví dụ. Timeout phải dựa trên latency distribution và deadline end-to-end. Cửa sổ quá nhỏ dễ dao động; quá lớn phản ứng chậm. minimumCalls tránh mở breaker chỉ vì 1 lỗi trong 1 request.

Kết hợp timeout, retry, jitter và bulkhead

Một pipeline thường hợp lý: deadline tổng → timeout mỗi attempt → retry hữu hạn với exponential backoff và jitter → circuit breaker → bulkhead giới hạn concurrency. Thứ tự cụ thể phụ thuộc thư viện, nhưng mục tiêu phải rõ:

  • Không attempt nào vượt ngân sách thời gian còn lại.
  • Chỉ retry lỗi transient và operation an toàn/idempotent.
  • Không retry khi breaker đang Open.
  • Jitter tránh nhiều instance đồng loạt thử lại.
  • Bulkhead ngăn một dependency chiếm hết thread hoặc connection.

Không đặt retry ở nhiều tầng. Hãy chọn một tầng chịu trách nhiệm để tránh retry amplification.

Fallback phải đúng ngữ nghĩa

Fallback tốt có thể là cache hơi cũ, bỏ phần gợi ý không thiết yếu, xếp yêu cầu idempotent vào queue hoặc trả trạng thái “tạm thời chưa khả dụng”. Không được trả dữ liệu giả như thể thành công cho thanh toán, tồn kho hay phân quyền.

Phân biệt phản hồi degraded với dữ liệu thật bằng metadata và metric. Cache fallback cần TTL, nguồn gốc và giới hạn stale rõ ràng.

Pseudocode triển khai

result = breaker.execute('inventory-reserve', () =>
  retryWithJitter(2, remainingDeadline, () =>
    inventory.reserve(orderId, items, idempotencyKey)
  )
).catch(error => {
  if (error.isCircuitOpen || error.isTimeout) {
    return queueForRetry(orderId);
  }
  throw error;
});

Với thao tác ghi, idempotency key hoặc cơ chế deduplication là bắt buộc vì timeout không cho biết dependency đã commit hay chưa.

Quan sát những gì?

  • Trạng thái và số lần chuyển Closed/Open/Half-Open.
  • Tỷ lệ success, failure, slow call và short-circuit.
  • Latency theo dependency, operation và outcome.
  • Số probe Half-Open cùng kết quả.
  • Fallback rate, queue depth và tuổi dữ liệu cache.

Cảnh báo nên dựa vào tác động: breaker Open kéo dài, nhiều instance đồng loạt mở, fallback vượt ngưỡng hoặc SLO người dùng bị ảnh hưởng. Một lần chuyển trạng thái ngắn chưa chắc cần đánh thức on-call.

Những lỗi thiết kế thường gặp

  • Dùng breaker thay cho timeout.
  • Retry ngay cả khi breaker đã Open.
  • Một breaker chung cho các dependency độc lập.
  • Health check trả 200 nhưng operation thật vẫn lỗi.
  • Half-Open cho quá nhiều request.
  • Fallback che giấu mất dữ liệu hoặc sai nghiệp vụ.
  • Không kiểm thử state transition và concurrency.

Checklist production

  • Deadline và timeout được đo từ latency thực tế.
  • Danh sách exception/status được tính hoặc bỏ qua đã rõ.
  • Retry hữu hạn, có backoff+jitter và chỉ dùng cho operation phù hợp.
  • Breaker phân tách theo dependency/operation.
  • Half-Open giới hạn probe.
  • Fallback bảo toàn ngữ nghĩa nghiệp vụ.
  • Có dashboard, alert và fault-injection test.
  • Runbook nêu cách force-open/reset khi cần.

Kết luận

Circuit Breaker không sửa dependency bị lỗi; nó bảo vệ phần còn lại của hệ thống trong lúc dependency phục hồi. Giá trị thực sự đến từ việc ghép đúng timeout, retry có jitter, bulkhead, fallback và observability. Thiết kế tốt sẽ fail nhanh, giảm tải có chủ đích và mở lại bằng một lượng probe vừa đủ.

Tài liệu tham khảo

Thảo luận

Bình luận 0

Đăng nhập để bình luận

Bạn cần có tài khoản để tham gia thảo luận và trả lời độc giả khác.

Đăng nhậpĐăng ký

Chưa có bình luận. Hãy là người đầu tiên chia sẻ ý kiến.