Rate limiting в Rust: обзор библиотек и инструментов
Rate limiting (ограничение частоты запросов) — критически важный механизм защиты веб-сервисов от перегрузок, DDoS-атак и злоупотреблений. В экосистеме Rust доступно несколько зрелых библиотек для реализации rate limiting: от низкоуровневых алгоритмов до готовых middleware для популярных веб-фреймворков. В этой статье рассмотрим три ключевых подхода: governor (алгоритм GCRA), leaky-bucket (дырявое ведро) и интеграцию с Actix/Axum.
1. Библиотека governor — алгоритм GCRA
governor — самая популярная библиотека rate limiting в Rust, основанная на Generic Cell Rate Algorithm (GCRA). Этот алгоритм используется в сетевых протоколах и позволяет гибко настраивать как пиковую нагрузку, так и среднюю скорость.
Ключевые возможности:
- Поддержка нескольких ключей (IP, User-Agent, API-ключ)
- Настраиваемый burst (всплеск трафика)
- Асинхронная работа через
tokioилиasync-std - Потокобезопасность без блокировок
Пример настройки лимита 100 запросов в минуту с burst 20:
use governor::{DefaultKeyedRateLimiter, Quota, RateLimiter};
use std::num::NonZeroU32;
use std::time::Duration;
#[tokio::main]
async fn main() {
// Лимит: 100 запросов в минуту, burst 20
let quota = Quota::with_period(Duration::from_secs(60))
.unwrap()
.allow_burst(NonZeroU32::new(20).unwrap());
let limiter = DefaultKeyedRateLimiter::::new(quota);
// Проверка для пользователя "user123"
match limiter.check_key("user123") {
Ok(_) => println!("Запрос разрешён"),
Err(_) => println!("Лимит превышен, статус 429"),
}
}
2. Библиотека leaky-bucket — дырявое ведро
Алгоритм дырявого ведра реализован в библиотеке leaky-bucket. Он моделирует ведро с водой, которое наполняется запросами и протекает с постоянной скоростью. Подходит для сглаживания пиковых нагрузок.
Особенности:
- Простая модель: ведро ёмкостью N запросов
- Скорость утечки — количество запросов в секунду
- Поддержка максимума ожидающих запросов
Пример с лимитом 5 запросов в секунду и ведром на 10:
use leaky_bucket::RateLimiter;
use std::time::Duration;
#[tokio::main]
async fn main() {
let limiter = RateLimiter::builder()
.initial(10) // начальное количество токенов
.max(10) // максимальный размер ведра
.interval(Duration::from_millis(200)) // пополнение каждые 200 мс
.build();
// Попытка получить токен
if limiter.try_acquire().is_ok() {
println!("Запрос обработан");
} else {
println!("Ведро пусто, отказ");
}
}
3. Middleware для веб-фреймворков
Готовые middleware значительно упрощают интеграцию rate limiting в веб-серверы на Actix и Axum.
Actix + governor
use actix_web::{web, App, HttpServer, HttpRequest, HttpResponse, middleware::from_fn};
use governor::{DefaultKeyedRateLimiter, Quota};
use std::num::NonZeroU32;
use std::time::Duration;
async fn rate_limit_middleware(
req: HttpRequest,
limiter: web::Data<DefaultKeyedRateLimiter<String>>,
) -> Result<HttpResponse, actix_web::Error> {
let client_ip = req.peer_addr()
.map(|addr| addr.to_string())
.unwrap_or_default();
match limiter.check_key(&client_ip) {
Ok(_) => Ok(HttpResponse::Ok().body("OK")),
Err(_) => Ok(HttpResponse::TooManyRequests().body("Too Many Requests")),
}
}
Axum + tower-governor
use axum::{Router, response::IntoResponse, routing::get};
use tower_governor::{governor::GovernorLayer, GovernorConfig};
#[tokio::main]
async fn main() {
let config = GovernorConfig::default(); // 1000 req/min
let app = Router::new()
.route("/", get(|| async { "Hello, world!" }))
.layer(GovernorLayer { config });
axum::Server Также в библиотеке
Отправка email на Java: библиотека Jakarta Mail (JavaMail)
Отправка email на JavaScript (Node.js): nodemailer, sendgrid, mailgun
GraphQL в C++: библиотека cppgraphqlgen для современных API
Очереди задач в TypeScript: обзор библиотек и реализация