Designing an API rate limiter


Designing an API rate limiter is crucial for maintaining system performance and preventing abuse. Here’s a high-level overview of how you can design a scalable API rate limiter:

Components:

  1. Rate Limiter Middleware: This sits between the client and the server, handling rate limiting logic.
  2. Counter Storage: Stores the count of requests made by each user or IP address. In-memory data stores like Redis are commonly used for fast access.
  3. Rate Limiting Algorithm: Determines how to count and limit requests (e.g., token bucket, leaky bucket).

High-Level Design:

  1. Client Request: The client sends a request to the API endpoint.
  2. Middleware Check: The rate limiter middleware checks the counter for the client’s IP/user ID.
  3. Counter Update: If the counter is below the limit, the middleware allows the request and increments the counter. If the limit is reached, the middleware blocks or throttles the request.
  4. Counter Expiry: The counter expires after a set time period, allowing the client to make requests again.

Example Implementation:

Here’s a simplified example using Redis for counter storage:

#include <iostream>
#include <string>
#include <unordered_map>
#include <chrono>

class RateLimiter {
public:
    RateLimiter(int limit, int timeWindow) : limit(limit), timeWindow(timeWindow) {}

    bool allowRequest(const std::string& clientId) {
        auto now = std::chrono::steady_clock::now();
        auto& counter = counters[clientId];

        if (now - counter.lastRequestTime > timeWindow) {
            counter.count = 0;
        }

        if (counter.count < limit) {
            counter.count++;
            counter.lastRequestTime = now;
            return true;
        } else {
            return false;
        }
    }

private:
    struct Counter {
        int count = 0;
        std::chrono::steady_clock::time_point lastRequestTime;
    };

    int limit;
    int timeWindow;
    std::unordered_map<std::string, Counter> counters;
};

int main() {
    RateLimiter rateLimiter(10, std::chrono::seconds(60));
    std::string clientId = "client123";

    for (int i = 0; i < 15; ++i) {
        if (rateLimiter.allowRequest(clientId)) {
            std::cout << "Request allowed" << std::endl;
        } else {
            std::cout << "Request denied" << std::endl;
        }
    }

    return 0;
}

Explanation:

  • RateLimiter Class: Manages counters for each client.
  • allowRequest Method: Checks if the client has exceeded the rate limit.
  • Counter Expiry: Resets the counter after the time window expires.

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *