Một client gửi 10,000 request mỗi giây đến API của bạn. Server bị quá tải. Mọi client khác đều nhận “503 Service Unavailable.”
Một service upstream bị sập. App của bạn vẫn cứ gọi đến nó. Các thread xếp hàng chờ. Toàn bộ app trở nên chậm chạp với mọi người.
Đây không phải giả thuyết. Nó xảy ra trong mọi hệ thống production. Rate Limiting và Circuit Breaker là hàng phòng thủ của bạn.
Phần 1: Nền tảng (Mô hình tư duy)
Rate Limiting = Đèn Giao thông
Rate Limiter là Đèn Giao thông tại một ngã tư bận rộn.
- Nó không chặn tất cả xe cộ. Nó điều tiết luồng.
- Đèn đỏ: “Bạn gửi quá nhiều request rồi. Chờ 60 giây.” (HTTP 429 Too Many Requests).
- Đèn xanh: “Bạn vẫn trong giới hạn. Đi qua.”
Nó bảo vệ ai: Service của bạn khỏi bị áp đảo bởi bất kỳ một client nào. Cũng bảo vệ khỏi DDoS và data scraping.
Circuit Breaker = Hộp Cầu dao
Circuit Breaker bảo vệ app của bạn khỏi dependency đang lỗi (API bên ngoài, database).
Hãy nghĩ về hộp cầu dao điện. Nếu xảy ra chập điện (quá nhiều dòng điện), cầu dao nhảy (ngắt mạch). Điện lập tức ngừng chảy. Nhà bạn không bị cháy.
Các trạng thái:
- CLOSED (Bình thường): Request đi qua đến dependency.
- OPEN (Đã nhảy): Dependency thất bại quá nhiều lần. Ngừng gọi. Trả về fallback ngay lập tức.
- HALF-OPEN (Đang thử): Sau một khoảng timeout, cho phép một request thử nghiệm. Thành công → CLOSED. Thất bại → OPEN lại.
| |
Phần 2: Điều tra (Các thuật toán Rate Limiting)
1. Fixed Window (Cửa sổ cố định)
Đơn giản nhất. Cho phép N request mỗi cửa sổ thời gian (ví dụ: 100/phút).
- Vấn đề: Một client gửi 100 request lúc 12:59. Rồi 100 cái nữa lúc 13:00. Thực tế là họ đánh bạn 200 request trong 2 giây ngay tại ranh giới.
2. Sliding Window Log (Cửa sổ trượt)
Theo dõi timestamp của mọi request. Đếm xem có bao nhiêu cái trong 60 giây qua.
- Ưu: Chính xác. Không có vấn đề bùng nổ ranh giới.
- Nhược: Tốn bộ nhớ. Phải lưu từng timestamp.
3. Token Bucket (Tốt nhất cho API)
Một cái thùng chứa token, được nạp đầy đều đặn (ví dụ: 10 token/giây, tối đa 100). Mỗi request tiêu tốn 1 token. Nếu thùng rỗng: 429.
- Ưu: Cho phép bùng phát ngắn (tối đa bằng dung tích thùng). Tốc độ dài hạn ổn định.
- Nhược: Phức tạp hơn một chút.
| |
Phần 3: Chẩn đoán (Trạng thái Circuit Breaker)
| |
Theo dõi trạng thái Circuit Breaker
| Trạng thái | Điều đang xảy ra | Hành động |
|---|---|---|
| CLOSED (Bình thường) | Mọi thứ hoạt động | Theo dõi tỷ lệ lỗi |
| OPEN (Đã nhảy) | Dependency đang lỗi | Báo động on-call. Phục vụ fallback. |
| HALF-OPEN | Đang phục hồi | Theo dõi chặt request thử nghiệm |
Phần 4: Giải pháp (Pattern thực tế)
1. Retry với Exponential Backoff
Đừng thử lại ngay. Hãy chờ, rồi chờ lâu hơn.
| |
Tại sao cần Jitter? Không có jitter, tất cả client thất bại đều thử lại cùng một lúc → đám đông sấm sét → service đang phục hồi lại bị sập ngay lập tức.
2. Bulkhead Pattern (Vách ngăn)
Cô lập các phần khác nhau của hệ thống để một lỗi không lan sang phần khác.
| |
Mô hình tư duy chốt hạ
| |
Quy tắc độ bền:
- Mọi lời gọi ra ngoài đều phải có timeout.
- Mọi lần retry phải có exponential backoff + jitter.
- Nếu dependency lỗi liên tục, mở circuit — fail nhanh.
- Rate limit theo user/IP, không chỉ giới hạn toàn cục.
