Vì sao cần Rate Limit (giới hạn sử dụng)?
- Trong một phòng chat Twitch có nhiều người tham gia, nếu có một spammer mà không có giới hạn sử dụng thì spammer đó có thể lấn át toàn bộ cuộc trò chuyện.
- Thông qua giới hạn sử dụng, mỗi người dùng có thể có cơ hội tham gia một cách công bằng.
- Rate Limiter (bộ giới hạn sử dụng) kiểm soát lưu lượng của dịch vụ bằng cách chặn các yêu cầu vượt quá hạn mức đã đặt trong một khoảng thời gian nhất định. Điều này hữu ích không chỉ để kiểm soát spam trong chat.
- Ví dụ, trong form đăng nhập, có thể dùng giới hạn sử dụng để kìm hãm các cuộc tấn công brute force nhưng vẫn cho phép một số ít lần đoán sai.
- Các API endpoint cũng thường được áp dụng giới hạn sử dụng để ngăn một người dùng đơn lẻ độc chiếm tài nguyên.
- Nếu cho phép người dùng chỉ được gọi một API endpoint tốn kém 100 lần mỗi phút, có thể dùng bộ đếm để theo dõi 100 lần hit mỗi phút, và các yêu cầu sau đó sẽ bị chặn.
- Đây là Fixed Window Limiter, một trong những thuật toán giới hạn sử dụng đơn giản nhất.
- Đây là một cách phổ biến để kiểm soát lưu lượng dịch vụ.
Thuật toán Fixed windows
- Số lượng yêu cầu bị giới hạn trong một cửa sổ thời gian cố định.
- Ở đầu mỗi cửa sổ thời gian, bộ đếm yêu cầu được đặt lại về 0.
- Ưu điểm
- Dễ triển khai và dễ hiểu.
- Dễ dự đoán đối với người dùng.
- Nhược điểm
- Nếu yêu cầu bắt đầu gần cuối cửa sổ thời gian, có thể cho phép burst tăng vọt tới gấp đôi giới hạn.
- Ví dụ thực tế: GitHub API dùng bộ giới hạn tốc độ theo cửa sổ thời gian cố định, cho phép 5.000 yêu cầu mỗi giờ.
- Thay vì đặt thời điểm bắt đầu của cửa sổ theo các khoảng cố định, mỗi cửa sổ thời gian có thể được tạo tại thời điểm yêu cầu đầu tiên của người dùng trong cửa sổ đó.
- Với cách tiếp cận này, việc thông báo cho người dùng biết còn bao lâu đến cửa sổ tiếp theo là đặc biệt quan trọng.
Thuật toán Sliding windows
- Thay vì làm mới toàn bộ dung lượng cùng một lúc, sliding window bổ sung dung lượng từng yêu cầu một.
- Ưu điểm
- Làm mượt phân bố lưu lượng yêu cầu.
- Phù hợp với tải cao.
- Nhược điểm
- Kém dễ dự đoán hơn với người dùng so với cửa sổ thời gian cố định.
- Việc lưu timestamp của từng yêu cầu tiêu tốn nhiều tài nguyên.
- Vì sliding window hữu ích nhất trong các kịch bản lưu lượng cao, nên việc thuật toán cơ bản lại tiêu tốn nhiều tài nguyên trở thành một điểm bất lợi.
- Do đó, hầu hết các bộ giới hạn tốc độ sliding window trong thực tế đều dùng cách xấp xỉ.
- Cách xấp xỉ này tính số yêu cầu được cho phép trong cửa sổ thời gian cố định trước đó và trong cửa sổ thời gian cố định hiện tại, rồi gán trọng số cho các yêu cầu được cho phép ở cửa sổ trước theo mức độ chồng lấp với cửa sổ thời gian trôi kết thúc ở thời điểm hiện tại.
- Cách xấp xỉ này giới hạn yêu cầu gần như theo cùng một tỷ lệ nhưng hiệu quả hơn rất nhiều.
- Ví dụ thực tế: bộ giới hạn tốc độ có thể cấu hình của Cloudflare dùng sliding window xấp xỉ.
Thuật toán Token buckets
- Thay vì thời lượng của cửa sổ thời gian, hãy hình dung một bucket được nạp đầy bằng các "token" với tốc độ cố định.
- Mỗi yêu cầu sẽ rút một token từ bucket này, và nếu bucket trống thì yêu cầu tiếp theo sẽ bị chặn.
- Dung lượng của bucket thể hiện số lượng yêu cầu tối đa mà một burst có thể hỗ trợ.
- Khoảng thời gian bổ sung thể hiện khoảng cách trung bình dài hạn giữa các yêu cầu được phép.
- Một trong những ưu điểm chính của thuật toán này là có thể có burst và dung lượng trung bình riêng biệt mà không cần nhiều bộ giới hạn tốc độ khác nhau.
- Ưu điểm
- Cho phép burst lưu lượng cao nhưng vẫn áp dụng tốc độ yêu cầu trung bình dài hạn.
- Linh hoạt hơn cho người dùng vì cho phép lưu lượng tăng đột biến trong phạm vi chấp nhận được.
- Nhược điểm
- Khó truyền đạt các giới hạn và thời gian bổ sung cho người dùng hơn so với cửa sổ thời gian cố định.
- Ví dụ thực tế
- Stripe dùng token bucket với giới hạn 500 và khoảng bổ sung 0,01 giây cho mỗi người dùng, nhờ đó cho phép duy trì 100 yêu cầu mỗi giây nhưng vẫn cho phép burst tối đa 500 yêu cầu.
- Gói miễn phí GPT-3.5 của OpenAI dùng token bucket với giới hạn 200 và khoảng bổ sung 86400 giây/200, nên bị giới hạn ở 200 yêu cầu mỗi ngày.
Những điểm cần cân nhắc khi áp dụng rate limit
- Cần có kho lưu trữ bền vững cho rate limiter.
- Nếu kết nối của server tới kho lưu trữ bền vững bị lỗi, nên cho phép toàn bộ yêu cầu thay vì chặn chúng.
- Có thể tùy chọn điều tiết lưu lượng burst.
- Cần chọn khóa phù hợp (ID người dùng, API key, v.v.).
- Cần hiển thị các lỗi giới hạn tốc độ hữu ích (thời gian chờ đến yêu cầu tiếp theo, mã trạng thái HTTP 429, response header
x-ratelimit-*, v.v.).
2 bình luận
Đọc bài tóm tắt bằng tiếng Hàn xong, mình nghĩ kiểu “Ừ thì hiểu nó là gì rồi, nhưng chẳng phải đều là cùng một nội dung sao?”, nhưng khi đọc bài gốc ở liên kết thì thấy nó thực sự được giải thích rất hay và phần trực quan hóa cũng cực kỳ thỏa mãn! 👍👍👍
Ý kiến trên Hacker News
Tóm tắt các bình luận trên Hacker News
Một số điểm cần cân nhắc thêm từ kinh nghiệm lâu năm:
Trong môi trường multi-tenant, fair queuing là cách tiếp cận tối ưu để ngăn chặn tấn công DoS: Mỗi client được cấp một hàng đợi riêng, và một routine chạy nền sẽ lặp qua từng hàng đợi để xử lý request. Client gửi request spam chỉ làm tắc nghẽn hàng đợi của chính họ.
Kinh nghiệm triển khai mã xử lý phía client: Luôn thắc mắc chiến lược backoff nào là tối ưu khi chạm rate limit. Đọc về các đánh đổi từ góc nhìn của dịch vụ rất thú vị.
Lời chúc mừng: Đây là bài viết có phần trực quan hóa xuất sắc nhất cho một nội dung ngắn, rất giàu thông tin và trình bày trọng tâm rất tốt.
Thuật toán GCRA: Có vẻ là một thuật toán tốt hơn cho rate limiting. Mong rằng nó sẽ được biết đến và sử dụng rộng rãi hơn.
Làm rất tốt: Có thể cảm nhận được bài viết này đã được đầu tư rất nhiều thời gian và công sức. Làm tốt lắm.
Vấn đề rate-limiting trên AWS Lambda: Đã cố triển khai rate-limiting bằng NodeJS, nhưng trên AWS Lambda timer hoạt động kỳ lạ khiến kết quả vượt quá mục tiêu. Kiểm thử cục bộ thì qua nhưng trên Lambda thì thất bại. Không rõ là do timer hay do thư viện.
Cách xử lý khi lớp rate limiting bị bão hòa: Tò mò liệu có lựa chọn nào khác ngoài CF không. Cũng muốn biết các quy tắc nftable hiệu quả đến đâu trong việc phòng thủ trước tấn công DoS trên một VPS nhỏ.
Những lúc từng cần tài nguyên này: Đây là kiểu tài nguyên đã nhiều lần cần đến trong sự nghiệp. Rất vui vì giờ nó đã tồn tại.
Người hâm mộ trực quan hóa dữ liệu: Tò mò không biết có đang dùng D3 hay không.