Rate limiting в C++: библиотеки и инструменты для контроля запросов

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Rate limiting в C++: полное руководство по ограничению запросов

Rate limiting (ограничение скорости запросов) — это критически важный механизм для защиты серверов, API и распределённых систем от перегрузок, DDoS-атак и случайных всплесков трафика. В C++ реализация rate limiting требует эффективных алгоритмов и правильного выбора библиотек. В этой статье мы разберём основные подходы, популярные библиотеки и приведём готовые примеры кода.

Что такое rate limiting и зачем он нужен?

Rate limiting устанавливает максимальное количество запросов, которое клиент или система может выполнить за определённый промежуток времени. Основные цели:

  • Защита от злоупотреблений и перегрузки сервера
  • Обеспечение равномерного распределения ресурсов между пользователями
  • Предотвращение DDoS-атак и брутфорс-атак
  • Контроль потребления API-квот

Основные алгоритмы rate limiting

В C++ чаще всего используются три классических алгоритма:

1. Token Bucket (Ведро токенов)

Самый популярный алгоритм. Представляет собой "ведро" с токенами, которые пополняются с постоянной скоростью. Каждый запрос забирает один токен. Если токенов нет — запрос отклоняется.

#include <chrono>
#include <mutex>

class TokenBucket {
private:
    double tokens;
    double maxTokens;
    double refillRate; // токенов в секунду
    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 (Дырявое ведро)

Запросы поступают в очередь (ведро), которая обрабатывается с фиксированной скоростью. Если ведро переполняется — запросы отбрасываются.

#include <queue>
#include <chrono>

class LeakyBucket {
private:
    std::queue<int> bucket;
    size_t capacity;
    double leakRate; // запросов в секунду
    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 (Скользящее окно с логом)

Хранит временные метки запросов и отбрасывает те, что выходят за пределы окна. Более точный, но требует больше памяти.

Популярные библиотеки C++ для rate limiting

Хотя стандартная библиотека C++ не содержит готовых решений, существуют проверенные библиотеки:

  • Boost.TokenBucket — часть библиотеки Boost.Utilities. Предоставляет готовую реализацию Token Bucket. Требует Boost 1.75+.
  • libcurl с опцией CURLOPT_MAX_RECV_SPEED_LARGE — для ограничения скорости загрузки/отправки данных по сети.
  • Abseil (Google) — содержит absl::synchronization::BlockingCounter для синхронизации, но не имеет готового rate limiter — потребуется реализация поверх.
  • Poco::Util::RateLimiter — в библиотеке Poco (начиная с версии 1.12) есть встроенная поддержка ограничения скорости.

Пример использования Boost.TokenBucket

<                    

Рекомендаций