System Design

Rate limiting với token bucket: bài học từ Stripe cho API và ứng dụng AI

Tóm tắt

Token bucket cho phép burst ngắn nhưng giữ tốc độ trung bình trong giới hạn. Stripe dùng bốn lớp limiter; với ứng dụng AI, giới hạn theo token và số agent đồng thời, và luôn dark launch trước khi chặn thật.

Một script lỗi của khách hàng gửi hàng nghìn request mỗi giây, hệ thống chậm lại cho tất cả mọi người. Hoặc với API AI: một vòng lặp agent không dừng đốt sạch ngân sách token trong một đêm. Rate limiting là lớp phòng thủ đầu tiên. Bài viết kinh điển của Stripe "Scaling your API with rate limiters" chia sẻ bốn loại limiter họ dùng trong production, và thuật toán token bucket đứng sau.

Token bucket hoạt động thế nào?

  • Mỗi người dùng có một "xô" chứa tối đa N token.
  • Token được thêm vào xô với tốc độ cố định (ví dụ 10 token/giây), đầy thì thôi.
  • Mỗi request lấy một token; xô rỗng thì request bị từ chối (HTTP 429).

Ưu điểm: cho phép burst ngắn (dùng hết xô một lúc) nhưng giữ tốc độ trung bình trong giới hạn. Stripe triển khai bằng Redis để mọi server dùng chung trạng thái.

# Giả mã token bucket
tokens = min(capacity, tokens + (now - last) * rate)
if tokens >= 1:
    tokens -= 1; allow()
else:
    reject(429, retry_after=(1 - tokens) / rate)

Bốn loại limiter của Stripe

LoạiGiới hạnMục đích
Request rate limiterSố request mỗi giây cho mỗi người dùngQuan trọng nhất; chặn một người làm ảnh hưởng tất cả
Concurrent requests limiterSố request đang xử lý cùng lúcBảo vệ endpoint tốn tài nguyên, chậm
Fleet usage load shedderDành sẵn phần năng lực cho request quan trọngKhi quá tải, bỏ request ít quan trọng trước
Worker utilization load shedderTheo mức bận của workerPhòng tuyến cuối, giảm tải dần theo mức ưu tiên

Áp dụng cho ứng dụng AI

  • Giới hạn theo token, không chỉ theo request: một request LLM có thể tốn gấp trăm lần request khác. Đặt xô theo số token đầu vào/đầu ra.
  • Giới hạn concurrency cho agent: mỗi người dùng chỉ chạy vài agent cùng lúc.
  • Tầng phía trên nhà cung cấp: Claude API cũng có rate limit; limiter của bạn nên chặn trước khi chạm giới hạn đó, và đọc header retry-after khi nhận 429.
  • Ưu tiên lưu lượng: request người dùng thật quan trọng hơn job nền; tách hàng đợi.

Rủi ro và lưu ý

  • Bật đột ngột làm vỡ khách hàng: Stripe khuyên chạy "dark launch" (chỉ ghi log, chưa chặn) để xem ai sẽ bị ảnh hưởng.
  • Thông báo lỗi mơ hồ: trả 429 kèm thông tin còn bao lâu thì thử lại; tài liệu hoá giới hạn.
  • Redis thành điểm lỗi đơn: quyết định trước khi Redis chết thì cho qua hay chặn hết (fail open/closed).
  • Retry đồng loạt: client nên retry với exponential backoff và jitter, nếu không sẽ tạo bão retry.

Áp dụng thế nào?

  • Dev: Bắt đầu với request rate limiter theo người dùng; dùng thư viện có sẵn thay vì tự viết.
  • Tech Lead: Thêm limiter theo token và concurrency cho mọi endpoint gọi LLM; theo dõi tỷ lệ 429.
  • PM: Định nghĩa hạn mức theo gói dịch vụ; đây vừa là bảo vệ hệ thống vừa là công cụ định giá.

Nguồn & tham khảo

  1. Scaling your API with rate limiters — Stripe Blog