Limitación de tasa en Rust: revisión de bibliotecas y herramientas
La limitación de tasa (rate limiting) es un mecanismo crítico para proteger servicios web contra sobrecargas, ataques DDoS y abusos. En el ecosistema de Rust, hay varias bibliotecas maduras para implementar limitación de tasa: desde algoritmos de bajo nivel hasta middleware listos para usar en frameworks web populares. En este artículo, analizaremos tres enfoques clave: governor (algoritmo GCRA), leaky-bucket (cubo con fugas) y la integración con Actix/Axum.
1. Biblioteca governor — algoritmo GCRA
governor es la biblioteca de limitación de tasa más popular en Rust, basada en el Generic Cell Rate Algorithm (GCRA). Este algoritmo se utiliza en protocolos de red y permite configurar de manera flexible tanto la carga máxima como la velocidad promedio.
Características clave:
- Soporte para múltiples claves (IP, User-Agent, clave API)
- Burst (ráfaga de tráfico) configurable
- Funcionamiento asíncrono mediante
tokiooasync-std - Seguridad para subprocesos sin bloqueos
Ejemplo de configuración de límite de 100 solicitudes por minuto con burst de 20:
use governor::{DefaultKeyedRateLimiter, Quota, RateLimiter};use std::num::NonZeroU32;use std::time::Duration;
#[tokio::main]async fn main() { // Límite: 100 solicitudes por minuto, burst 20 let quota = Quota::with_period(Duration::from_secs(60)) .unwrap() .allow_burst(NonZeroU32::new(20).unwrap()); let limiter = DefaultKeyedRateLimiter::::new(quota); // Verificación para el usuario "user123" match limiter.check_key("user123") { Ok(_) => println!("Solicitud permitida"), Err(_) => println!("Límite excedido, estado 429"), }} 2. Biblioteca leaky-bucket — cubo con fugas
El algoritmo del cubo con fugas está implementado en la biblioteca leaky-bucket. Modela un cubo de agua que se llena con solicitudes y se vacía a una velocidad constante. Es adecuado para suavizar picos de carga.
Características:
- Modelo simple: cubo con capacidad de N solicitudes
- Velocidad de fuga: cantidad de solicitudes por segundo
- Soporte para un máximo de solicitudes en espera
Ejemplo con límite de 5 solicitudes por segundo y cubo de 10:
use leaky_bucket::RateLimiter;use std::time::Duration;
#[tokio::main]async fn main() { let limiter = RateLimiter::builder() .initial(10) // cantidad inicial de tokens .max(10) // tamaño máximo del cubo .interval(Duration::from_millis(200)) // recarga cada 200 ms .build(); // Intento de obtener un token if limiter.try_acquire().is_ok() { println!("Solicitud procesada"); } else { println!("Cubo vacío, rechazado"); }}3. Middleware para frameworks web
Los middleware listos para usar simplifican enormemente la integración de la limitación de tasa en servidores web con Actix y 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")), }}