Giải thích về giới hạn tốc độ API: Thuật toán, tiêu đề và xử lý lỗi 429
Giới hạn tốc độ bảo vệ API khỏi tình trạng quá tải và lạm dụng. Tìm hiểu cách hoạt động của các thuật toán chính, phản hồi 429 tốt trông như thế nào và khách hàng nên dừng lại như thế nào bằng cách sử dụng mô phỏng mà chúng tôi đã chạy.
- Giới hạn tỷ lệ giới hạn số lượng yêu cầu mà khách hàng có thể thực hiện trong một khoảng thời gian.
- Nhóm mã thông báo cho phép tăng vọt trong thời gian ngắn trong khi thực thi tốc độ trung bình.
- Một cửa sổ cố định đơn giản có thể cho phép vượt qua gấp đôi giới hạn ở ranh giới cửa sổ.
- Trả về 429 Quá nhiều yêu cầu với tiêu đề Thử lại sau và yêu cầu khách hàng dừng lại với tình trạng giật hình.
Một tập lệnh có lỗi gọi API của bạn theo một vòng lặp chặt chẽ. Không có giới hạn, nó có thể làm chậm dịch vụ của mọi người dùng khác hoặc tiêu tốn một khoản chi phí lớn trên đám mây. Giới hạn tốc độ API là rào chắn ngăn không cho một khách hàng nào lấy nhiều hơn mức chia sẻ công bằng của nó.
Để hiển thị cách hoạt động của các thuật toán phổ biến, chúng tôi đã viết các phiên bản Python nhỏ và cung cấp cho chúng thời gian yêu cầu mô phỏng. Các kết quả đầu ra dưới đây đến từ lần chạy đó. Chúng là các mô hình giảng dạy chứ không phải mã sản xuất và các cổng thực có nhiều tính năng hơn.
Giới hạn tỷ lệ là gì?
Giới hạn tốc độ tính các yêu cầu trên mỗi khách hàng và từ chối hoặc trì hoãn các yêu cầu vượt quá giới hạn đã thỏa thuận, chẳng hạn như 100 yêu cầu mỗi phút. Một ý tưởng liên quan, điều tiết, thường có nghĩa là làm chậm lại các yêu cầu thay vì từ chối chúng. hạn ngạch thường là mức trợ cấp lớn hơn trong thời gian dài hơn, chẳng hạn như 10.000 cuộc gọi mỗi tháng theo gói giá.
Tại sao API cần nó
- Tính ổn định: lưu lượng truy cập tăng đột biến không thể làm quá tải cơ sở dữ liệu hoặc các dịch vụ hạ nguồn.
- Công bằng: một khách hàng nặng ký không thể bỏ đói những khách hàng khác.
- Bảo mật: các giới hạn làm chậm các nỗ lực đăng nhập và tìm kiếm thô bạo.
- Kiểm soát chi phí: các hoạt động tốn kém, chẳng hạn như lệnh gọi mô hình AI, luôn nằm trong ngân sách.
Giới hạn tốc độ là một biện pháp kiểm soát cốt lõi trong Top 10 Bảo mật API OWASP, với mức tiêu thụ tài nguyên không hạn chế. Hướng dẫn kiểm tra API với Postman của chúng tôi cho biết cách gửi các yêu cầu lặp lại cần thiết để kiểm tra nó.
Nhóm mã thông báo
Hãy tưởng tượng một cái xô chứa tối đa 5 mã thông báo. Mỗi yêu cầu cần một mã thông báo. Mã thông báo được nạp lại với tốc độ 1 mỗi giây và nhóm không bao giờ chứa nhiều hơn 5. Nếu nhóm trống, yêu cầu sẽ bị từ chối.
class TokenBucket:
def __init__(self, capacity, refill_per_sec):
self.capacity = capacity
self.rate = refill_per_sec
self.tokens = capacity
self.last = 0.0
def allow(self, now):
elapsed = now - self.last
self.tokens = min(self.capacity, self.tokens + elapsed * self.rate)
self.last = now
if self.tokens >= 1:
self.tokens -= 1
return True
return False
Chúng tôi đã gửi 7 yêu cầu cùng một lúc, sau đó nhiều hơn nữa:
burst of 7 at t=0: [True, True, True, True, True, False, False]
t=2.0: [True, True, False]
t=10: 5 allowed of 10
5 cái đầu tiên trôi qua như một vụ nổ, sau đó cái xô trống rỗng. Hai giây sau, 2 mã thông báo đã được nạp lại, vì vậy có thêm 2 yêu cầu nữa được thông qua. Sau một thời gian dài tạm dừng, nhóm đã đầy trở lại nhưng bị giới hạn ở mức 5. Hoạt động liên tục rồi ổn định này phù hợp với lưu lượng truy cập thực, đó là lý do tại sao nhóm mã thông báo lại phổ biến trong các cổng API. nhóm bị rò rỉ là một họ hàng gần có khả năng xử lý các yêu cầu ở tốc độ cố định, làm trơn tru đầu ra thay vì cho phép bùng nổ.
Cửa sổ cố định và cửa sổ trượt
Bộ đếm cửa sổ cố định là cách tiếp cận đơn giản nhất: cho phép 10 yêu cầu mỗi phút và đặt lại bộ đếm khi phút thay đổi. Nó có một lỗ hổng được biết đến ở ranh giới. Chúng tôi đã gửi 10 yêu cầu ở tốc độ 59,9 giây và 10 yêu cầu khác ở tốc độ 60,0 giây, với giới hạn là 10 yêu cầu trên mỗi cửa sổ 60 giây:
fixed window allowed around boundary: 20 of 20
sliding log allowed around boundary: 10 of 20
Cửa sổ cố định cho phép tất cả 20 yêu cầu trong một phần mười giây, gấp đôi tốc độ dự kiến, vì chúng rơi vào hai cửa sổ khác nhau. Nhật ký trượt ghi nhớ thời gian của mỗi yêu cầu gần đây và đếm những yêu cầu đó trong 60 giây qua, do đó, nó chỉ cho phép chính xác 10.
Sự đánh đổi là bộ nhớ. Nhật ký trượt lưu trữ dấu thời gian cho mỗi yêu cầu. Bộ đếm cửa sổ trượt là một vị trí trung gian phổ biến. Nó ước tính tốc độ bằng cách trộn số lượng cửa sổ hiện tại và trước đó, sử dụng ít bộ nhớ với độ chính xác cao.
So sánh thuật toán
| Thuật toán | bùng nổ | Độ chính xác | Bộ nhớ |
|---|---|---|---|
| Cửa sổ cố định | Lên đến 2x ở ranh giới | Thấp | Rất thấp |
| Nhật ký trượt | Không | Chính xác | Cao |
| Quầy cửa sổ trượt | nhỏ | Tốt | Thấp |
| Nhóm mã thông báo | Cho phép tối đa công suất | Tốt | Thấp |
| Xô bị rò rỉ | Làm mịn ra | Tốt | Thấp |
Hạn chế bằng cách nào
- Khóa API hoặc ID người dùng: tùy chọn công bằng nhất cho các API được xác thực.
- Địa chỉ IP: hữu ích cho các điểm cuối công cộng nhưng nhiều người dùng có thể chia sẻ một IP và những kẻ tấn công có thể xoay vòng chúng.
- Điểm cuối: các hoạt động tốn kém, chẳng hạn như tìm kiếm, xuất hoặc đăng nhập, xứng đáng có giới hạn chặt chẽ hơn.
- Cấp gói: khách hàng miễn phí và trả phí thường có các giới hạn khác nhau.
Điểm cuối đăng nhập cần được chăm sóc đặc biệt. Giới hạn cả theo tài khoản và IP, vì vậy những kẻ tấn công không thể đơn giản truyền bá các dự đoán trên nhiều IP hoặc nhiều tài khoản.
Phản hồi 429
Khi khách hàng vượt quá giới hạn, hãy trả về HTTP 429 Quá Nhiều Yêu cầu, chứ không phải 500 hoặc 403. Hãy bao gồm các tiêu đề cho khách hàng biết điều gì đã xảy ra và khi nào cần thử lại. Mô phỏng của chúng tôi đã tạo ra bộ này cho một khách hàng không còn yêu cầu nào:
HTTP/1.1 429 Too Many Requests
RateLimit-Limit: 100
RateLimit-Remaining: 0
RateLimit-Reset: 30
Retry-After: 30
Retry-After là tiêu đề HTTP tiêu chuẩn. Các tiêu đề RateLimit-* đến từ bản nháp IETF và nhiều API sử dụng các biến thể X-RateLimit-* của riêng chúng. Dù bạn chọn gì, hãy ghi lại nó. Để biết thêm về mã trạng thái, hãy xem Bảng tóm tắt mã trạng thái HTTP của chúng tôi.
Xử lý giới hạn với tư cách là khách hàng
Việc thử lại ngay sau 429 sẽ khiến mọi việc trở nên tồi tệ hơn. Nếu hàng nghìn khách hàng thực hiện việc đó cùng lúc, họ sẽ tấn công máy chủ theo từng đợt đồng bộ. Cách khắc phục là thời gian chờ theo cấp số nhân kèm theo hiện tượng giật hình: đợi lâu hơn sau mỗi lần thất bại và thêm tính ngẫu nhiên.
def backoff(attempt, base=0.5, cap=30, rng=random.Random(4)):
return round(min(cap, base * 2 ** attempt) * rng.random(), 2)
[backoff(a) for a in range(6)]
# [0.12, 0.1, 0.79, 0.62, 0.53, 6.43]
Đây là tình trạng “jitter hoàn toàn”: thời gian chờ ngẫu nhiên giữa số 0 và mức trần tăng theo cấp số nhân. Sự chờ đợi có vẻ bất thường, và đó chính là vấn đề. Khách hàng tản ra thay vì thử lại cùng nhau. Chúng tôi đã tạo hạt giống cho trình tạo ngẫu nhiên để có thể sao chép đầu ra.
Danh sách kiểm tra của khách hàng: tôn trọng Retry-After khi có, giới hạn số lần thử lại, chỉ thử lại các yêu cầu an toàn để lặp lại và xem tiêu đề yêu cầu còn lại để bạn có thể giảm tốc độ trước khi đạt đến giới hạn.
Giới hạn tỷ lệ phân phối
Với một số máy chủ API phía sau bộ cân bằng tải, mỗi máy chủ tự đếm sẽ cho phép máy khách vượt quá giới hạn bằng cách phân bổ các yêu cầu trên chúng. Các nhóm thường giữ bộ đếm trong một cửa hàng dùng chung chẳng hạn như Redis, với các hoạt động nguyên tử hoặc một tập lệnh ngắn để hai máy chủ không thể cùng lấy mã thông báo cuối cùng. Các cổng như Kong, NGINX, Envoy và cổng API đám mây cung cấp cấu hình này. Chúng tôi không chạy thiết lập phân tán cho bài viết này.
Giới hạn tỷ lệ thử nghiệm
- Gửi yêu cầu đến giới hạn và xác nhận chúng thành công.
- Gửi thêm một lần nữa và xác nhận 429 với tiêu đề chính xác.
- Đợi thời gian đặt lại và xác nhận yêu cầu thành công lần nữa.
- Kiểm tra giới hạn cho mỗi khóa: việc sử dụng của một khách hàng không được chặn một khóa khác.
- Kiểm tra ranh giới giữa các cửa sổ để tìm sự cố bùng phát kép.
- Sử dụng công cụ tải, như được đề cập trong kiểm tra tải và kiểm tra sức chịu đựng, để kiểm tra hành vi trong điều kiện đồng thời nhiều.
Trong các thử nghiệm đơn vị, hãy thêm thời gian hiện tại, giống như mô phỏng của chúng tôi thực hiện với now, để các thử nghiệm không bao giờ phải ngủ.
Thiết kế các giới hạn mà người dùng có thể chấp nhận
Việc chọn số cũng quan trọng như việc chọn thuật toán. Bắt đầu từ lưu lượng truy cập thực tế: xem xét số lượng yêu cầu mà khách hàng hợp pháp nặng nhất của bạn thực hiện mỗi phút và đặt giới hạn một cách thoải mái trên mức đó. Giới hạn chặn việc sử dụng bình thường sẽ tạo ra các phiếu hỗ trợ chứ không phải sự an toàn.
- Công bố các giới hạn trong tài liệu API của bạn, theo từng điểm cuối và theo từng gói.
- Cảnh báo trước khi chặn. Tiêu đề hiển thị các yêu cầu còn lại cho phép các ứng dụng khách hoạt động tốt tự giảm tốc độ.
- Cung cấp các lựa chọn thay thế cho việc bỏ phiếu nhiều, chẳng hạn như webhook, điểm cuối hàng loạt hoặc các trang lớn hơn.
- Theo dõi tỷ lệ 429. Sự gia tăng đột ngột có thể đồng nghĩa với một cuộc tấn công, một bản phát hành ứng dụng khách có lỗi hoặc các giới hạn hiện quá chặt chẽ.
- Cố tình cấp các ngoại lệ, chẳng hạn như nâng cao giới hạn cho đối tác, được ghi lại trong cấu hình thay vì mã hóa cứng.
Đồng thời quyết định điều gì sẽ xảy ra với các yêu cầu đến vượt quá giới hạn. Một số API xếp hàng nhanh một số lượng nhỏ yêu cầu bổ sung thay vì từ chối chúng, điều này giúp giảm bớt các đột biến ngắn. Những người khác ưu tiên cho các điểm cuối thiết yếu, chẳng hạn như thanh toán, hơn các điểm cuối ít quan trọng hơn như phân tích, để lưu lượng truy cập quan trọng tiếp tục được lưu chuyển khi hệ thống chịu áp lực.
Lời kết
Giới hạn tỷ lệ tốt là một hợp đồng giữa API và khách hàng. Máy chủ chọn một thuật toán hợp lý, thường là nhóm mã thông báo hoặc cửa sổ trượt và giải thích rõ ràng các giới hạn của nó bằng 429 và Thử lại sau. Máy khách tôn trọng những tín hiệu đó và lùi lại với tình trạng jitter. Bắt đầu với các giới hạn hào phóng cho mỗi khóa API, theo dõi mức sử dụng thực tế và chỉ thắt chặt ở những nơi bạn cần.
Câu hỏi thường gặp
Giới hạn tỷ lệ API là gì?
Đó là giới hạn về số lượng yêu cầu mà khách hàng có thể thực hiện đối với API trong một thời gian nhất định, chẳng hạn như 100 yêu cầu mỗi phút. Yêu cầu vượt quá giới hạn sẽ bị từ chối hoặc bị trì hoãn.
HTTP 429 có nghĩa là gì?
429 Quá nhiều yêu cầu có nghĩa là máy khách đã vượt quá giới hạn tốc độ. Phản hồi thường bao gồm tiêu đề Retry-After cho biết phải đợi bao lâu.
Thuật toán nhóm mã thông báo là gì?
Mỗi yêu cầu sử dụng mã thông báo từ nhóm được nạp lại với tốc độ ổn định đến mức tối đa. Nó cho phép các đợt bùng phát ngắn trong khi thực thi tốc độ trung bình.
Sự khác biệt giữa giới hạn tốc độ và điều tiết là gì?
Giới hạn tốc độ thường từ chối các yêu cầu vượt quá giới hạn. Thay vào đó, việc điều tiết thường làm chậm hoặc xếp hàng chúng. Các thuật ngữ thường được sử dụng thay thế cho nhau.
Khách hàng nên xử lý giới hạn tỷ lệ như thế nào?
Tôn trọng việc thử lại sau, thử lại với độ trễ và biến động theo cấp số nhân, giới hạn số lần thử lại và giảm tốc độ khi các yêu cầu còn lại sắp hết.
Tiếp tục học hỏi
Cần trợ giúp về kiểm tra, WordPress hoặc SEO?
Chúng tôi giúp các nhóm phát triển phần mềm tốt hơn và phát triển trang web của họ. Hãy cho chúng tôi biết bạn đang làm gì và chúng tôi sẽ đề xuất bước tiếp theo rõ ràng.
Thêm hướng dẫn về thử nghiệm, AI và phát triển hiện đại
Bạn thích bài viết này? Chọn một chủ đề và chuyển ngay sang phần hướng dẫn mới nhất của chúng tôi.
Giải thích về ảo giác AI: Tại sao các mô hình ngôn ngữ lại tạo nên mọi thứ và cách giảm thiểu nó
Ảo giác AI đã giải thích: chúng là gì, tại sao mô hình ngôn ngữ tạo ra chúng, các loại phổ biến, cách giảm thiểu chúng bằng cách căn cứ và nhắc nhở …
Đọc bài viết →DevOpsGiải thích về các biến môi trường: Tệp .env, bí mật và cấu hình được thực hiện đúng
Các biến môi trường được giải thích bằng các ví dụ Python mà chúng tôi đã chạy: đọc và thiết lập chúng, tại sao mọi giá trị đều là một chuỗi, tệp .e…
Đọc bài viết →Phát triển phần mềmGiải thích về giới hạn tỷ lệ API: Thuật toán, tiêu đề và xử lý lỗi 429
Giới hạn tốc độ API được giải thích bằng mô phỏng mà chúng tôi đã chạy: nhóm mã thông báo, cửa sổ cố định, cửa sổ trượt, 429 phản hồi, tiêu đề giới …
Đọc bài viết →Tự động hóa kiểm thửChế giễu bằng Python: unittest.mock, patch và những sai lầm khiến bài kiểm tra nói dối
Mô phỏng bằng Python với unittest.mock, đã được thử nghiệm: Mock và return_value, side_effect, vá lỗi nơi sử dụng tên, thông số kỹ thuật và thông số…
Đọc bài viết →Kiểm thử phần mềmGiải thích về phạm vi bảo hiểm của mã: Phạm vi tuyến so với chi nhánh và ý nghĩa thực sự 100%
Phạm vi bảo hiểm mã được giải thích bằng cách chạy phạm vi bảo hiểm thực tế: phạm vi bảo hiểm dòng, chi nhánh và điều kiện, đọc báo cáo, lý do tại s…
Đọc bài viết →Cơ sở dữ liệu & SQLDELETE vs TRUNCATE vs DROP trong SQL: Sự khác biệt, khôi phục và thời điểm sử dụng mỗi loại
DELETE vs TRUNCATE vs DROP được giải thích bằng SQL đã được thử nghiệm: mỗi loại loại bỏ, khôi phục, kích hoạt, đặt lại danh tính, tốc độ và Postgre…
Đọc bài viết →Cơ sở dữ liệu & SQLGiải thích về Chế độ xem SQL: Tạo, sử dụng và tránh những cạm bẫy, kèm theo ví dụ
Chế độ xem SQL được giải thích bằng các truy vấn chúng tôi đã chạy: tạo chế độ xem, kết quả trực tiếp, ẩn cột, hiệu suất, chế độ xem có thể cập nhật…
Đọc bài viết →Phát triển phần mềmGiao diện TypeScript so với loại: Sự khác biệt thực sự, được thử nghiệm bằng trình biên dịch
Giao diện TypeScript so với loại, được kiểm tra bằng trình biên dịch thực: cả hai có thể làm gì, chỉ một người có thể làm gì, hợp nhất khai báo, mở …
Đọc bài viết →Phát triển phần mềmGiải thích về Python *args và **kwargs: Hàm linh hoạt với ví dụ rõ ràng
Python *args và **kwargs được giải thích bằng mã chúng tôi đã chạy: đóng gói và giải nén, thứ tự tham số, đối số chỉ từ khóa và chỉ vị trí, trình tr…
Đọc bài viết →Phát triển phần mềmHàm Lambda của Python: Cú pháp, cách sử dụng thực tế và khi nào không nên sử dụng chúng
Các hàm lambda của Python được giải thích bằng mã chúng tôi đã chạy: cú pháp, sắp xếp bằng khóa, bản đồ và bộ lọc, các phần đóng, bẫy liên kết muộn …
Đọc bài viết →Trí tuệ nhân tạoĐại lý AI là gì? Cách chúng hoạt động, với vòng lặp tác nhân đơn giản, bạn có thể chạy
Tác nhân AI là gì? Hướng dẫn đơn giản về vòng lặp tác nhân, công cụ, bộ nhớ và lan can, với một vòng lặp Python nhỏ mà chúng tôi đã chạy, những rủi …
Đọc bài viết →DevOpsGiám sát và Khả năng quan sát: Sự khác biệt thực sự, với nhật ký, số liệu và dấu vết
Giải thích về giám sát và khả năng quan sát: lỗi đã biết và chưa biết, nhật ký, số liệu và dấu vết, hướng dẫn về sự cố thanh toán, tín hiệu vàng, Op…
Đọc bài viết →DevOpsDocker Volumes vs Bind Mounts: Duy trì dữ liệu vùng chứa đúng cách
Giải thích về khối lượng Docker và liên kết gắn kết: tại sao dữ liệu vùng chứa biến mất, khối lượng được đặt tên, liên kết gắn kết, tmpfs, ví dụ về …
Đọc bài viết →Tự động hóa kiểm thửTDD vs BDD: Key Differences, One Feature Built Both Ways and When to Use Each
TDD và BDD được giải thích bằng một tính năng giảm giá được xây dựng theo cả hai cách: tái cấu trúc màu đỏ-xanh với mã chúng tôi đã chạy, kịch bản C…
Đọc bài viết →Phát triển phần mềmGit merge vs rebase: khác biệt, ví dụ và khi nào dùng cái nào
Git merge vs rebase được giải thích bằng đầu ra log thực tế, bảng so sánh, quy tắc vàng của rebase và quy trình làm việc nhóm an toàn.
Đọc bài viết →Phát triển phần mềmList comprehension trong Python: cú pháp, ví dụ và khi nào nên tránh
List comprehension trong Python: cú pháp, lọc dữ liệu, if-else, vòng lặp lồng nhau, thời gian đo thực tế và khi nào vòng lặp for thông thường tốt hơn.
Đọc bài viết →Cơ sở dữ liệu & SQLGiải thích SQL JOIN kèm ví dụ (Inner, Left, Right, Full)
Hiểu SQL JOIN từng bước với bảng và truy vấn mẫu: INNER, LEFT, RIGHT, FULL, CROSS và SELF, cùng lỗi thường gặp và mẹo hiệu năng.
Đọc bài viết →