Tóm tắt: Khả năng chịu lỗi không đến từ việc thử lại nhiều hơn, mà từ việc sử dụng ngân sách thời gian và tài nguyên có giới hạn.
Thuật ngữ chính: Timeout: thời gian chờ tối đa; Circuit Breaker: tạm ngừng gọi dịch vụ đang lỗi; Bulkhead: tách riêng tài nguyên để một dịch vụ lỗi không kéo theo phần khác.
Bài toán
Thiếu Timeout khiến yêu cầu giữ tài nguyên quá lâu. Thử lại ở nhiều lớp có thể nhân số lần gọi xuống dưới. Nếu mọi dịch vụ dùng chung một pool kết nối, chỉ một nhà cung cấp chậm cũng có thể làm toàn bộ hệ thống cạn tài nguyên.
Vì sao cách làm đơn giản chưa đủ
Nếu ba layer đều thử lại ba lần, một yêu cầu có thể thành 27 downstream attempt. Thử lại quyền sở hữu phải rõ.
Circuit breaker bảo vệ năng lực xử lý sau khi đã biết lỗi. Timeout và bulkhead bảo vệ ngay trong lúc lỗi còn được phát hiện.
Luồng xử lý
budget còn lại→Bulkhead
concurrency cô lập→Attempt
timeout và idempotency→Circuit breaker
fail nhanh có kiểm soát
Quyết định kiến trúc
Budget toàn journey
Chừa thời gian cho local work và phản hồi. Sau đó, chia phần còn lại cho downstream thay vì mỗi thành phần phụ thuộc có timeout mới.
thử lại theo error semantics
thử lại connection reset và một số throttling. Không thử lại kiểm tra error hoặc non-idempotent ghi mơ hồ.
Cô lập pool
Dùng connection, thread hoặc semaphore limit riêng để vendor chậm không làm đói thành phần phụ thuộc khác.
Phân tích chuyên sâu
Fallback đổi product semantics
Trả giá cũ hoặc giả payment thành công có thể tệ hơn unavailable rõ ràng. Product người phụ trách phải duyệt fallback.
Adaptive limit cần guardrail
Concurrency có thể phản ứng theo độ trễ. Tuy nhiên, cần min, max và phục hồi chậm để tránh dao động.
Các bước triển khai
- Propagate một end-to-end deadline và dừng khi budget hết.
- Chỉ thử lại operation transient, idempotent với backoff, jitter và attempt budget nhỏ.
- Cô lập concurrency theo thành phần phụ thuộc và shed load trước khi queue vô hạn.
Ví dụ kỹ thuật: lời gọi tới thành phần phụ thuộc hiểu deadline
remaining = request.deadline - now()
if remaining < minimumUsefulTime: return degraded()
with bulkhead.acquire(timeout = 20ms):
return retry(max = 2, jitter = true) {
vendor.call(timeout = min(300ms, remaining))
}Tính lại remaining deadline trước mỗi attempt và gắn idempotency key cho ghi được thử lại.
Các tình huống lỗi cần tính trước
- Fallback cache phục vụ data quá stale window.
- Half-open probe quá nhiều làm sập vendor đang phục hồi.
- thử lại tiếp tục sau khi client đã bỏ yêu cầu.
Tín hiệu cần giám sát
| Tín hiệu | Ý nghĩa |
|---|---|
| Deadline bị thành phần phụ thuộc tiêu thụ | Cho biết integration nào dùng hết journey budget. |
| thử lại amplification ratio | Đo downstream attempt trên mỗi incoming yêu cầu. |
| Bulkhead rejection và circuit trạng thái | Thể hiện saturation được chứa và quá trình phục hồi. |
Cách kiểm chứng thiết kế
- Inject riêng độ trễ, reset, throttling và invalid phản hồi.
- Làm lỗi một thành phần phụ thuộc và kiểm tra pool khác vẫn có năng lực xử lý.
- Mô phỏng partial recovery và xác nhận probe tăng dần.
Kế hoạch triển khai an toàn
Đo độ trễ và attempt hiện tại. Thêm timeout rõ nhưng chưa thử lại, sau đó cô lập pool rồi mới bật thử lại hẹp. Chạy circuit breaker ở observe-only trước enforcement và diễn tập mọi fallback.
Checklist trước khi đưa vào vận hành
- Chỉ một layer sở hữu thử lại cho một call path.
- Circuit trạng thái change có quyền can thiệp thủ công và recovery probe.
- Fallback trung thực về freshness và capability bị thiếu.
Kết luận
Integration bền vững giữ lỗi trong budget đã biết và bảo toàn năng lực xử lý cho phần còn khỏe.
