Rate Limiting in C++: A Complete Guide to Request Limiting
Rate limiting is a critically important mechanism for protecting servers, APIs, and distributed systems from overloads, DDoS attacks, and random traffic spikes. In C++, implementing rate limiting requires efficient algorithms and the right choice of libraries. In this article, we will break down the main approaches, popular libraries, and provide ready-made code examples.
What is rate limiting and why is it needed?
Rate limiting sets the maximum number of requests a client or system can perform within a specific time period. The main goals are:
- Protection from abuse and server overload
- Ensuring fair distribution of resources among users
- Preventing DDoS attacks and brute-force attacks
- Controlling API quota consumption
Basic rate limiting algorithms
In C++, three classic algorithms are most commonly used:
1. Token Bucket
The most popular algorithm. It represents a "bucket" of tokens that are replenished at a constant rate. Each request takes one token. If there are no tokens, the request is rejected.
#include <chrono>#include <mutex>
class TokenBucket {private: double tokens; double maxTokens; double refillRate; // tokens per second std::chrono::steady_clock::time_point lastRefill; std::mutex mtx;
public: TokenBucket(double maxTokens, double refillRate) : tokens(maxTokens), maxTokens(maxTokens), refillRate(refillRate) { lastRefill = std::chrono::steady_clock::now(); }
bool tryConsume() { std::lock_guard<std::mutex> lock(mtx); refill(); if (tokens >= 1.0) { tokens -= 1.0; return true; } return false; }
private: void refill() { auto now = std::chrono::steady_clock::now(); auto elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(now - lastRefill).count() / 1000.0; tokens = std::min(maxTokens, tokens + elapsed * refillRate); lastRefill = now; }};2. Leaky Bucket
Requests enter a queue (bucket) which is processed at a fixed rate. If the bucket overflows, requests are discarded.
#include <queue>#include <chrono>
class LeakyBucket {private: std::queue<int> bucket; size_t capacity; double leakRate; // requests per second std::chrono::steady_clock::time_point lastLeak; std::mutex mtx;
public: LeakyBucket(size_t capacity, double leakRate) : capacity(capacity), leakRate(leakRate) { lastLeak = std::chrono::steady_clock::now(); }
bool addRequest(int request) { std::lock_guard<std::mutex> lock(mtx); leak(); if (bucket.size() < capacity) { bucket.push(request); return true; } return false; }
private: void leak() { auto now = std::chrono::steady_clock::now(); auto elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(now - lastLeak).count() / 1000.0; size_t toRemove = static_cast<size_t>(elapsed * leakRate); while (toRemove > 0 && !bucket.empty()) { bucket.pop(); toRemove--; } lastLeak = now; }};3. Sliding Window Log
Stores timestamps of requests and discards those that fall outside the window. More accurate, but requires more memory.
Popular C++ libraries for rate limiting
Although the C++ standard library does not contain ready-made solutions, there are proven libraries:
-
Also in library
Recommendations