Menu
ESC

Nhập từ khóa để tìm kiếm

↑↓ Di chuyển
Enter Mở
ESC Đóng

Đang tải...

Bài 24 — Rate Limiting, Quota, và Throttling

Technical Product Manager Bài 24/60

Mở đầu — vì sao bài này quan trọng

Hãy tưởng tượng bạn vừa ra mắt một API public cho sản phẩm của mình — ví dụ một API tra cứu thông tin đơn hàng cho các cửa hàng trên sàn thương mại điện tử. Mọi thứ chạy mượt trong tuần đầu. Rồi một sáng thứ Hai, một đối tác viết sai vòng lặp trong code của họ, gọi API của bạn 50.000 lần mỗi giây thay vì 50 lần. Server của bạn quá tải, database treo, và toàn bộ khách hàng khác — những người trả tiền đầy đủ — không truy cập được nữa. Một lỗi của một client kéo sập trải nghiệm của tất cả mọi người.

Đây chính xác là lý do tồn tại của Rate Limiting, Quota và Throttling. Với vai trò Technical PM, bạn không cần tự code thuật toán token bucket, nhưng bạn PHẢI hiểu các cơ chế này đủ sâu để: (1) thiết kế pricing tier dựa trên giới hạn sử dụng, (2) quyết định hạn mức hợp lý cho từng nhóm khách hàng, (3) trao đổi với kỹ sư về cách trả lỗi và header chuẩn, và (4) cân bằng giữa bảo vệ hệ thống và trải nghiệm developer. Đây là một trong những nơi mà quyết định kỹ thuật và quyết định kinh doanh gặp nhau trực tiếp nhất. Một giới hạn quá chặt làm mất khách; quá lỏng làm sập hệ thống. Bài này dạy bạn cách tìm điểm cân bằng đó.

Khái niệm cốt lõi

Ba thuật ngữ này thường bị dùng lẫn lộn, nhưng chúng giải quyết ba vấn đề khác nhau. Hãy phân biệt rõ.

Rate Limiting — Giới hạn tốc độ

Rate Limiting kiểm soát số lượng request trong một khoảng thời gian ngắn, ví dụ "tối đa 100 request mỗi phút". Mục tiêu là chống lại các đợt gọi dồn dập (burst) làm quá tải hệ thống ngay lập tức. Đơn vị đo thường là requests per second (RPS) hoặc requests per minute (RPM). Khi client vượt giới hạn, server trả về mã lỗi HTTP 429 Too Many Requests.

Quota — Hạn mức tổng

Quota là tổng lượng sử dụng được phép trong một chu kỳ dài, ví dụ "1 triệu request mỗi tháng" hoặc "10 GB dữ liệu mỗi ngày". Quota gắn liền với mô hình kinh doanh: gói Free cho 10.000 request/tháng, gói Pro cho 1 triệu request/tháng. Khác với rate limit (đo theo giây/phút), quota đo theo ngày/tháng và thường reset theo chu kỳ billing. Một client có thể không bao giờ vượt rate limit (gọi rải đều) nhưng vẫn cạn quota tháng.

Throttling — Điều tiết

Throttling là cơ chế phản ứng khi vượt giới hạn. Có hai cách xử lý chính:

  • Hard throttling (từ chối): request vượt ngưỡng bị reject ngay với lỗi 429.
  • Soft throttling (làm chậm): server vẫn xử lý nhưng cố tình trì hoãn (thêm độ trễ), hoặc đưa request vào hàng đợi xử lý sau. Đây gọi là "request shaping".
Nói cách khác: Rate limit và quota là luật, còn throttling là cách thực thi luật đó.

Các thuật toán phổ biến (PM cần nhận biết, không cần code)

Khi làm việc với kỹ sư, bạn sẽ nghe đến vài thuật toán. Hiểu khác biệt giúp bạn ra quyết định trade-off:

  • Fixed Window (cửa sổ cố định): đếm request trong từng khối thời gian cố định, ví dụ mỗi phút reset về 0. Đơn giản nhưng có lỗ hổng "burst ở ranh giới" — client có thể gọi 100 request vào giây cuối phút này và 100 request vào giây đầu phút sau, thực tế 200 request trong 2 giây.
  • Sliding Window (cửa sổ trượt): tính trên khoảng thời gian trượt liên tục, mượt hơn, chống được burst ở ranh giới, nhưng tốn tài nguyên hơn.
  • Token Bucket (xô token): mỗi client có một "xô" chứa token, được nạp đầy với tốc độ cố định. Mỗi request tiêu một token. Cho phép burst ngắn (dùng token tích lũy) nhưng vẫn giới hạn tốc độ trung bình. Đây là lựa chọn phổ biến nhất vì linh hoạt.
  • Leaky Bucket (xô rò): request đổ vào xô và "rò" ra với tốc độ đều, làm phẳng traffic. Tốt cho việc bảo vệ downstream cần tốc độ ổn định.

HTTP headers chuẩn — ngôn ngữ giao tiếp với developer

Đây là phần PM hay bỏ sót nhưng cực kỳ quan trọng cho Developer Experience. Một API tốt phải cho client biết họ còn bao nhiêu "lượt":

  • X-RateLimit-Limit: tổng giới hạn trong cửa sổ.
  • X-RateLimit-Remaining: số request còn lại.
  • X-RateLimit-Reset: thời điểm reset (thường là Unix timestamp).
  • Retry-After: khi đã bị 429, header này nói client nên chờ bao nhiêu giây trước khi thử lại.
Không có những header này, developer của client phải "đoán mò" và thường sẽ retry sai cách, làm tình hình tệ hơn.

Tình huống thực tế

Tình huống 1: Sàn TMĐT Việt Nam và đối tác logistics gây sập hệ thống

Một sàn thương mại điện tử lớn tại Việt Nam (gọi là sàn X) mở API cho các đối tác vận chuyển để cập nhật trạng thái giao hàng. Ban đầu họ không đặt rate limit vì "đối tác là người quen, tin tưởng được". Trong đợt sale 11/11, một đối tác triển khai tính năng đồng bộ mới, vô tình tạo một vòng lặp gọi API cập nhật trạng thái mỗi 200ms cho hàng chục nghìn đơn — tổng cộng khoảng 40.000 RPS dội vào endpoint. Database write quá tải, queue tắc nghẽn, và API trạng thái đơn hàng — endpoint mà chính khách mua hàng đang theo dõi — chậm tới mức timeout suốt 25 phút trong giờ vàng.

Diễn giải: Vấn đề không phải đối tác xấu, mà là không có lớp bảo vệ. Sau sự cố, đội PM và kỹ sư áp dụng token bucket với giới hạn 200 RPS mỗi đối tác (đủ rộng cho nhu cầu thật, vẫn chặn được loop lỗi), trả 429 kèm Retry-After, và tách riêng infrastructure cho endpoint ghi của đối tác khỏi endpoint đọc của người mua.

Bài học: "Tin tưởng đối tác" không phải là chiến lược kỹ thuật. Rate limit bảo vệ bạn khỏi cả lỗi vô tình lẫn lạm dụng cố ý. Và hãy luôn cô lập (isolate) các luồng traffic quan trọng với nhau.

Tình huống 2: Stripe — Rate limit như một phần của Developer Experience

Stripe, công ty thanh toán toàn cầu, áp rate limit khoảng 100 read và 100 write request mỗi giây ở chế độ live (con số minh họa cho mô hình). Điều đáng học không phải con số, mà là cách họ làm. Stripe trả về header rate limit đầy đủ, có tài liệu rõ ràng khuyến nghị client dùng exponential backoff (chờ tăng dần: 1s, 2s, 4s...) khi gặp 429, và họ phân biệt rate limit cho các thao tác nặng (như tạo nhiều object) với thao tác nhẹ.

Diễn giải: Stripe coi rate limit không phải là rào cản mà là một phần của hợp đồng API minh bạch. Developer biết chính xác giới hạn, biết cách xử lý khi chạm trần, và không bao giờ bị "bất ngờ". Đây là lý do API của họ được khen là dễ tích hợp.

Bài học: Với API-as-a-Product, rate limit được thiết kế tốt làm tăng độ tin cậy. Tài liệu, header, và hướng dẫn xử lý lỗi quan trọng ngang với bản thân con số giới hạn.

Tình huống 3: Startup SaaS đặt pricing tier qua quota

Một startup SaaS cung cấp API gửi SMS/OTP cho các app fintech ở Đông Nam Á. Họ thiết kế ba gói:

  • Free: 100 request/phút, quota 5.000 SMS/tháng — đủ để dev test và demo.
  • Growth: 1.000 request/phút, quota 100.000 SMS/tháng.
  • Enterprise: 10.000 request/phút, quota tùy chỉnh, có cam kết SLA.
Họ phát hiện nhiều khách Free cố "lách" bằng cách tạo nhiều tài khoản. Giải pháp: gắn quota theo cả tài khoản lẫn theo số điện thoại đích và theo IP, đồng thời thêm trang dashboard hiển thị mức tiêu thụ realtime để khách tự thấy mình sắp chạm trần và chủ động nâng gói.

Diễn giải: Quota ở đây chính là cấu trúc giá. Giới hạn Free vừa đủ để trải nghiệm nhưng không đủ để vận hành sản xuất, tạo động lực nâng cấp tự nhiên. Dashboard minh bạch biến giới hạn từ "bực bội" thành "tín hiệu mua hàng".

Bài học: Rate limit và quota không chỉ là kỹ thuật phòng thủ — chúng là đòn bẩy tăng trưởng (growth lever). Cách bạn cắt tier quyết định tỷ lệ chuyển đổi từ Free lên Paid.

Hướng dẫn từng bước

Khi bạn cần thiết kế chính sách rate limit/quota cho một API, hãy đi theo trình tự sau:

  • Xác định mục tiêu chính. Bạn đang chống quá tải (rate limit), kiếm tiền theo mức dùng (quota), hay cả hai? Mục tiêu khác nhau dẫn đến thiết kế khác nhau.
  • Đo baseline thực tế. Đừng đặt con số từ cảm tính. Hỏi kỹ sư: hiện tại 95% client gọi bao nhiêu RPS? Endpoint chịu tải tối đa bao nhiêu trước khi xuống cấp? Đặt giới hạn phủ được P95–P99 của khách dùng hợp lệ, đồng thời thấp hơn ngưỡng sập của hệ thống.
  • Chọn chiều giới hạn (dimension). Giới hạn theo cái gì: per API key, per user, per IP, hay per endpoint? Endpoint nặng (như export báo cáo) nên có giới hạn riêng chặt hơn endpoint nhẹ.
  • Phân tier theo nhóm khách. Free, Pro, Enterprise mỗi nhóm một con số. Đảm bảo bậc Free đủ để trải nghiệm nhưng tạo lý do nâng cấp.
  • Quyết định cơ chế throttling. Hard (trả 429) hay soft (làm chậm/xếp hàng)? API public thường dùng hard + header rõ ràng. Hệ thống nội bộ có thể dùng soft.
  • Chuẩn hóa phản hồi lỗi. Thống nhất với kỹ sư: trả 429, kèm Retry-After, kèm các header X-RateLimit-*, và body lỗi có message thân thiện giải thích nên làm gì.
  • Viết tài liệu rõ ràng. Ghi giới hạn của từng tier, khuyến nghị exponential backoff, ví dụ code xử lý 429. Đây là phần thuộc về Developer Experience.
  • Giám sát và lặp. Theo dõi tỷ lệ 429, khách nào hay chạm trần, có ai bị chặn oan không. Điều chỉnh dựa trên dữ liệu, không phải giả định.

Lỗi thường gặp & mẹo

Lỗi: Đặt giới hạn từ cảm tính. Chọn "1000 RPS nghe có vẻ hợp lý" mà không đo. Hãy luôn dựa vào dữ liệu sử dụng thực tế và ngưỡng chịu tải thật của hệ thống.

Lỗi: Trả lỗi mơ hồ. Trả 500 hoặc 403 thay vì 429, hoặc 429 mà không kèm Retry-After. Client không biết phải làm gì, sẽ retry liên tục và làm tải nặng thêm. Luôn trả đúng mã 429 với đầy đủ header.

Lỗi: Quên client sẽ retry. Khi bị chặn, code client thường tự động thử lại ngay lập tức, tạo "retry storm" còn tệ hơn. Mẹo: bắt buộc khuyến nghị exponential backoff kèm jitter (thêm độ ngẫu nhiên) trong tài liệu, để các client không retry đồng loạt cùng lúc.

Lỗi: Chỉ giới hạn theo một chiều. Chỉ giới hạn per IP thì khách dùng chung NAT (cùng văn phòng) bị tính chung; chỉ giới hạn per API key thì kẻ xấu tạo nhiều key. Mẹo: kết hợp nhiều chiều giới hạn.

Lỗi: Giới hạn quá chặt làm mất khách thật. Đừng để policy bảo vệ trở thành rào cản. Mẹo: theo dõi false positive — những khách hợp lệ bị chặn — và có cơ chế nâng giới hạn nhanh cho khách lớn.

Mẹo: Cân nhắc "burst allowance". Cho phép vượt ngắn hạn (qua token bucket) để xử lý các đỉnh tự nhiên, miễn là tốc độ trung bình vẫn trong giới hạn. Trải nghiệm mượt hơn nhiều so với chặn cứng tuyệt đối.

Mẹo: Tách giới hạn cho thao tác đọc và ghi. Ghi thường tốn tài nguyên hơn đọc nhiều lần, nên thường có giới hạn chặt hơn.

Bài tập thực hành

  • Thiết kế chính sách: Bạn là PM cho một API thời tiết phục vụ các app du lịch. Hãy phác thảo ba pricing tier (Free, Pro, Enterprise) với rate limit (RPM) và quota (request/tháng) cụ thể. Giải thích lý do chọn từng con số và bậc Free của bạn tạo động lực nâng cấp như thế nào.
  • Phân tích thuật toán: Giải thích bằng lời tại sao Fixed Window có lỗ hổng "burst ở ranh giới", và token bucket khắc phục điều đó ra sao. Vẽ một ví dụ với con số minh họa.
  • Soạn phản hồi 429: Viết ra cấu trúc đầy đủ của một HTTP response 429 lý tưởng — gồm status code, các header (Retry-After, X-RateLimit-*), và body JSON với message thân thiện hướng dẫn developer.
  • Tình huống ra quyết định: Một khách Enterprise phàn nàn họ liên tục bị 429 dù trả tiền cao nhất. Bạn sẽ hỏi kỹ sư những câu gì để chẩn đoán? Liệt kê ít nhất 4 câu hỏi và hành động bạn sẽ làm để vừa giữ khách vừa bảo vệ hệ thống.

Tóm tắt

Rate Limiting, Quota và Throttling là ba khái niệm bổ trợ nhau: rate limit kiểm soát tốc độ trong khoảng ngắn (chống burst, trả 429), quota kiểm soát tổng lượng trong chu kỳ dài (gắn với pricing), và throttling là cách thực thi (từ chối cứng hoặc làm chậm mềm). Là Technical PM, bạn không cần code thuật toán, nhưng cần hiểu đủ để chọn con số dựa trên dữ liệu thật, cắt pricing tier khôn ngoan, yêu cầu phản hồi lỗi chuẩn (429 + header + hướng dẫn backoff), và cân bằng giữa bảo vệ hệ thống với trải nghiệm developer. Hãy nhớ ba bài học cốt lõi: tin tưởng không thay được giới hạn kỹ thuật, rate limit tốt là một phần của Developer Experience chứ không phải rào cản, và quota chính là đòn bẩy tăng trưởng khi được thiết kế minh bạch.