Bạn đã bao giờ được yêu cầu nói chậm lại khi bạn đang nói quá nhanh không? Bộ giới hạn tốc độ API hoạt động tương tự cho các chương trình máy tính.
Bộ giới hạn tốc độ API (API Rate Limiter) là gì?
Một bộ giới hạn tốc độ API kiểm soát tần suất người dùng có thể gửi yêu cầu đến một dịch vụ. Nó giống như một cảnh sát giao thông cho dữ liệu, đảm bảo không ai chiếm dụng tất cả tài nguyên.
Tại sao sử dụng bộ giới hạn tốc độ?
- Ngăn chặn quá tải: Ngăn máy chủ bị sập do quá nhiều yêu cầu
- Sử dụng công bằng: Đảm bảo mọi người đều có lượt
- Bảo mật: Giúp chặn các cuộc tấn công làm tràn ngập hệ thống
Triển khai bộ giới hạn tốc độ API
Xác định chính sách giới hạn tốc độ của bạn
- Quyết định số lượng yêu cầu được phép trong mỗi cửa sổ thời gian
- Chọn kích thước cửa sổ thời gian (ví dụ: mỗi phút, giờ, ngày)
- Xác định xem giới hạn áp dụng toàn cục hay theo từng người dùng/IP
Chọn cơ chế lưu trữ
- Lưu trữ trong bộ nhớ (cho cài đặt máy chủ đơn)
- Bộ nhớ đệm phân tán như Redis (cho môi trường đa máy chủ)
- Cơ sở dữ liệu (để lưu trữ lâu dài và truy vấn phức tạp)
Thiết kế thành phần giới hạn tốc độ
- Tạo một hàm để kiểm tra xem một yêu cầu có được phép hay không
- Triển khai logic để đếm số yêu cầu trong cửa sổ thời gian
- Thêm cơ chế để đặt lại bộ đếm sau khi cửa sổ thời gian hết hạn
Triển khai theo dõi yêu cầu
- Tạo một định danh duy nhất cho mỗi khách hàng (ví dụ: khóa API, địa chỉ IP)
- Ghi lại mỗi yêu cầu với một dấu thời gian
- Loại bỏ các yêu cầu cũ nằm ngoài cửa sổ thời gian hiện tại
Thêm kiểm tra giới hạn tốc độ vào API của bạn
- Tích hợp bộ giới hạn tốc độ vào đường ống xử lý yêu cầu API của bạn
- Gọi bộ giới hạn tốc độ trước khi xử lý mỗi yêu cầu
Xử lý vi phạm giới hạn tốc độ
- Trả về mã trạng thái HTTP thích hợp (thường là 429 Too Many Requests)
- Bao gồm thông tin giới hạn tốc độ trong tiêu đề phản hồi
Tối ưu hóa hiệu suất
- Sử dụng cấu trúc dữ liệu hiệu quả (ví dụ: tập hợp được sắp xếp trong Redis)
- Triển khai bộ nhớ đệm để giảm tra cứu lưu trữ
Thêm giám sát và ghi nhật ký
- Theo dõi các lần chạm giới hạn tốc độ và gần chạm
- Thiết lập cảnh báo cho các vi phạm lặp đi lặp lại
Triển khai thông tin giới hạn tốc độ trong phản hồi
- Thêm tiêu đề hiển thị mức sử dụng và giới hạn hiện tại
- Cân nhắc cung cấp một điểm cuối để người dùng kiểm tra trạng thái giới hạn tốc độ của họ
Kiểm tra bộ giới hạn tốc độ
- Xác minh nó giới hạn yêu cầu đúng cách
- Đảm bảo nó đặt lại sau cửa sổ thời gian
- Kiểm tra các trường hợp biên và các điều kiện đua tiềm ẩn
Lập tài liệu chính sách giới hạn tốc độ
- Thông báo rõ ràng các giới hạn cho người dùng API
- Cung cấp hướng dẫn về các phương pháp tốt nhất để tránh chạm giới hạn
Xem xét các tính năng nâng cao
- Triển khai các cấp giới hạn tốc độ khác nhau cho các người dùng khác nhau
- Thêm xử lý đột biến để cho phép các đợt tăng đột ngột trong việc sử dụng
- Triển khai tiêu đề retry-after cho các khóa tạm thời
Ví dụ đơn giản trong Ruby on Rails
Lưu trữ trong bộ nhớ
class InMemoryRateLimiter
MAX_REQUESTS = 100
WINDOW_SIZE = 3600 # 1 hour in seconds
def initialize
@requests = {}
end
def allow_request?(user_id)
current_time = Time.now.to_i
@requests[user_id] ||= []
@requests[user_id].reject! { |timestamp| timestamp < current_time - WINDOW_SIZE }
if @requests[user_id].size < MAX_REQUESTS
@requests[user_id] << current_time
true
else
false
end
end
end
# In your controller:
def index
limiter = InMemoryRateLimiter.new
if limiter.allow_request?(current_user.id)
# Process the request
else
render json: { error: "Too many requests" }, status: :too_many_requests
end
endƯu điểm: Cực kỳ nhanh, đơn giản để triển khai
Nhược điểm: Không lưu trữ lâu dài, không mở rộng được trên nhiều máy chủ
Các phương pháp khác
Có nhiều phương pháp khác để thực hiện giới hạn tốc độ mà không sử dụng lưu trữ trong bộ nhớ. Dưới đây là một số phương pháp thay thế:
- Redis
- Lưu trữ trong cơ sở dữ liệu
- Lưu trữ dựa trên tệp
Mỗi phương pháp này đều có ưu và nhược điểm riêng:
Redis
- Ưu điểm: Nhanh, có khả năng mở rộng, lưu trữ lâu dài, hỗ trợ hệ thống phân tán
- Nhược điểm: Yêu cầu máy chủ Redis riêng biệt, cần thêm cơ sở hạ tầng
Redis xuất sắc trong các tình huống yêu cầu hiệu suất cao và hệ thống phân tán, khiến nó trở thành lựa chọn phổ biến cho việc giới hạn tốc độ trong môi trường sản xuất, mặc dù có thêm độ phức tạp trong việc quản lý máy chủ Redis.
class RedisRateLimiter
MAX_REQUESTS = 100
WINDOW_SIZE = 3600 # 1 hour in seconds
def initialize(user_id)
@user_id = user_id
@redis = Redis.new
end
def allow_request?
current_time = Time.now.to_i
key = "rate_limit:#{@user_id}"
# Removes all elements in the sorted set with a score between min and max (inclusive).
# We use it to remove all entries older than our time window (1 hour ago).
# This effectively "slides" our window, keeping only recent entries.
@redis.zremrangebyscore(key, 0, current_time - WINDOW_SIZE)
# Returns the number of elements in the sorted set.
# We use this to count how many requests have been made in our current time window.
current_count = @redis.zcard(key)
if current_count < MAX_REQUESTS
# Adds one or more members to a sorted set, or updates the score if it already exists.
# Here, we're adding an entry with the current timestamp as the score.
# The value is a unique string (timestamp plus random hex) to avoid collisions.
@redis.zadd(key, current_time, "#{current_time}.#{SecureRandom.hex(6)}")
@redis.expire(key, WINDOW_SIZE)
true
else
false
end
end
endCơ sở dữ liệu (ví dụ: PostgreSQL)
- Ưu điểm: Lưu trữ lâu dài, hoạt động với cơ sở dữ liệu hiện có, tốt cho các truy vấn phức tạp
- Nhược điểm: Chậm hơn Redis hoặc lưu trữ trong bộ nhớ, có thể tăng tải cho cơ sở dữ liệu chính
Dựa trên tệp
- Ưu điểm: Lưu trữ lâu dài, đơn giản, không yêu cầu dịch vụ bổ sung
- Nhược điểm: Chậm đối với lưu lượng truy cập cao, có thể gặp vấn đề về đồng thời
Lựa chọn tốt nhất phụ thuộc vào nhu cầu cụ thể của bạn, như yêu cầu về hiệu suất, nhu cầu lưu trữ lâu dài và quy mô của ứng dụng của bạn.
Đối với các ứng dụng Ruby
Các khái niệm và chiến lược giới hạn tốc độ mà chúng ta đã thảo luận có thể được áp dụng trên nhiều ngôn ngữ lập trình và framework khác nhau. Chúng không giới hạn ở Ruby hoặc Rails, mà có thể được điều chỉnh để phù hợp với bất kỳ stack công nghệ nào bạn đang làm việc.
Đối với các nhà phát triển Ruby, có một số gem có sẵn triển khai các khái niệm giới hạn tốc độ này, giúp bạn tiết kiệm công sức viết mọi thứ từ đầu. Một số gem phổ biến bao gồm:
- Rack::Attack https://github.com/rack/rack-attack: Middleware Rack để chặn & hạn chế các yêu cầu lạm dụng
- Rate Limiting https://github.com/iugu/rate-limiting: cung cấp công cụ để tạo các quy tắc có thể giới hạn tốc độ các route riêng biệt.
- Throttling https://github.com/kpumuk/throttling: Gem Throttling cung cấp cách cơ bản nhưng rất mạnh mẽ để hạn chế các hành động khác nhau của người dùng trong ứng dụng của bạn. Về cơ bản, bạn có thể chỉ định số lần một hành động có thể được thực hiện trong một khoảng thời gian nhất định.
Để sử dụng một trong những gem này, bạn thường thêm nó vào Gemfile của bạn và cấu hình nó theo nhu cầu của bạn.
Hãy nhớ rằng, mặc dù những gem này làm cho việc triển khai dễ dàng hơn trong Ruby, nhưng các nguyên tắc cơ bản vẫn giống nhau trên các ngôn ngữ khác. Cho dù bạn đang sử dụng Python, JavaScript, Java hay bất kỳ ngôn ngữ nào khác, bạn có thể áp dụng các chiến lược giới hạn tốc độ này bằng cách sử dụng các thư viện dành riêng cho ngôn ngữ hoặc tự triển khai logic.
Khóa chặt API của bạn: Các biện pháp bảo mật đơn giản (Whitelisting, JSON Web Tokens, API Keys, OAuth 2.0, Basic Authentication, Hash-based Message Authentication Code) https://vulehuan.com/vi/r/rmVaDJafBS0
