Skip to content

Thực hành: Thiết kế Distributed Rate Limiter

🎯 Mục tiêu

🎯 Sau bài thực hành này, bạn sẽ:

  • So sánh Token Bucket, Sliding Window, Fixed Window
  • Thiết kế rate limiter phân tán với Redis
  • Giải quyết consistency trong multi-region deployment
  • Xử lý race condition với atomic operations

Yêu cầu hệ thống

Functional: Giới hạn request theo user/IP/API key, multiple rules, HTTP 429, metrics.

Non-functional: Check dưới 1ms (p99), sai số <1%, fail-open khi down, 1M RPM.

So sánh thuật toán

Thuật toánƯu điểmNhược điểmUse case
Fixed WindowĐơn giảnBurst 2x tại biênInternal API
Sliding Window CounterCân bằngXấp xỉGeneral
Token BucketCho phép burst hợp lýCần tuningPublic API
Leaky BucketOutput ổn địnhKhông burstStreaming

Kiến trúc

Thiết kế chi tiết

Token Bucket với Redis

  • Key: ratelimit:{user_id}:{endpoint}, Fields: tokens, last_refill
  • Atomic Lua script: Tính refill → update → check → allow/deny trong 1 operation (tránh race condition)

Rules

Per-user (100 req/min free, 1000 premium), per-IP (50/min), per-endpoint (/api/upload 10/min). Most specific wins.

🎯 Scenario Choice

Multi-region Consistency

Deploy 2 region. User limit 100 req/min, gửi 60 đến mỗi region → bypass (120).

Centralized Redis: Consistency hoàn hảo, latency 50-100ms. Local + Async Sync: Latency thấp, eventual consistency. Split Quota: Chia 50/50, không sync nhưng lãng phí.

💡 Production chọn Local + Async Sync. Sai số 5-10% acceptable — rate limiting ngăn abuse, không cần exact.

Trắc nghiệm

🧠 Quiz

Câu 1: Token Bucket phù hợp hơn Fixed Window cho public API vì?

  • [ ] A) Ít memory hơn
  • [x] B) Cho phép burst hợp lý, Fixed Window cho phép 2x limit tại biên window
  • [ ] C) Không cần centralized storage
  • [ ] D) Fixed Window không implement được với Redis

💡 Fixed Window reset tại boundary: 100 req cuối phút 1 + 100 đầu phút 2 = 200 trong 2s. Token Bucket smooth hơn.

🧠 Quiz

Câu 2: Rate limiter bị down, xử lý thế nào?

  • [ ] A) Block mọi request (fail-closed)
  • [x] B) Cho request đi qua, log warning (fail-open) — availability quan trọng hơn
  • [ ] C) Dùng cached decision
  • [ ] D) Chuyển sang client-side limiting

💡 Rate limiter là safety mechanism. Fail-closed = toàn bộ API block, nghiêm trọng hơn vài request thừa.

🧠 Quiz

Câu 3: Sliding Window Counter ước lượng rate bằng cách nào?

  • [ ] A) Lưu timestamp mọi request rồi đếm
  • [ ] B) HyperLogLog ước lượng
  • [x] C) Kết hợp counter window hiện tại và trước theo tỷ lệ overlap
  • [ ] D) Chia sub-window nhỏ cộng tất cả counter

💡 Công thức: count = current + previous * overlap%. Ở phút 1:30: count_m2 + count_m1 * 0.5.