Rate Limiting en Rust: bibliotecas para limitar la frecuencia de solicitudes

Entrenador de Python en Línea para Principiantes

Aprende Python fácilmente sin sobrecargarte de teoría. Resuelve tareas prácticas con verificación automática, recibe pistas y escribe código directamente en el navegador, sin instalar nada.

Start Course

Rate Limiting en Rust: gestión eficiente de la carga

\n\n

Rate limiting (limitación de la frecuencia de solicitudes) es un mecanismo clave para la protección y optimización de servicios web, API y aplicaciones de red. En el ecosistema de Rust existen varias bibliotecas maduras que implementan diferentes algoritmos: desde el clásico token bucket hasta métodos adaptativos modernos. En este artículo analizaremos tres bibliotecas principales: governor, leaky-bucket y ratelimit, con ejemplos de código y recomendaciones para su elección.

\n\n

1. Biblioteca governor: el estándar de oro

\n\n

governor es la biblioteca más popular y flexible para rate limiting. Implementa el algoritmo Generic Cell Rate Algorithm (GCRA), que garantiza el cumplimiento preciso de los límites con una latencia mínima. Admite modos síncrono y asíncrono, middleware para Actix-web, Axum y Rocket.

\n\n

Ejemplo básico con governor

\n
use governor::{DefaultKeyedRateLimiter, Quota, RateLimiter};\nuse std::num::NonZeroU32;\nuse std::time::Duration;\n\nfn main() {\n    // Permitimos 5 solicitudes por segundo\n    let quota = Quota::per_second(NonZeroU32::new(5).unwrap());\n    let limiter = RateLimiter::direct(quota);\n\n    for i in 0..10 {\n        match limiter.check() {\n            Ok(_) => println!("Solicitud {} permitida", i),\n            Err(_) => println!("Solicitud {} rechazada (rate limit)", i),\n        }\n        std::thread::sleep(Duration::from_millis(100));\n    }\n}
\n\n

Variante asíncrona con espera

\n
use governor::{Quota, RateLimiter};\nuse std::num::NonZeroU32;\nuse tokio::time::{sleep, Duration};\n\n#[tokio::main]\nasync fn main() {\n    let limiter = RateLimiter::direct(Quota::per_second(\n        NonZeroU32::new(2).unwrap(),\n    ));\n\n    for i in 0..5 {\n        limiter.until_ready().await;\n        println!("Solicitud {} procesada", i);\n        sleep(Duration::from_millis(300)).await;\n    }\n}
\n\n

Características clave de governor:

\n
    \n
  • Soporte para límites por clave (por IP, por usuario) mediante KeyedRateLimiter
  • \n
  • Integración con middleware tower para servidores HTTP
  • \n
  • Estrategias configurables: espera, rechazo, desaceleración adaptativa
  • \n
  • Consumo mínimo de memoria (un contador atómico por limitador)
  • \n
\n\n

2. Biblioteca leaky-bucket: simplicidad y fiabilidad

\n\n

leaky-bucket implementa el algoritmo clásico del «cubo con fugas». Es ideal para suavizar picos de carga cuando se necesita garantizar un flujo uniforme de solicitudes. La biblioteca es ligera y no requiere dependencias externas.

\n\n

Ejemplo con leaky-bucket

\n
use leaky_bucket::RateLimiter;\nuse std::time::Duration;\n\n#[tokio::main]\nasync fn main() {\n    let limiter = RateLimiter::builder()\n        .initial(10)        // reserva inicial de tokens\n        .interval(Duration::from_secs(1))  // intervalo de recarga\n        .refill(5)          // cuántos tokens agregar por intervalo\n        .max(20)            // número máximo de tokens\n        .build();\n\n    for i in 0..15 {\n        limiter.acquire_one().await;\n        println!("Solicitud {} completada", i);\n    }\n}
\n\n

Características de leaky-bucket:

\n
    \n
  • Soporte para API asíncrona y bloqueante
  • \n
  • Posibilidad de configurar el modo «burst» (ráfagas cortas)
  • \n
  • Liberación automática de tokens durante la inactividad
  • \n
\n\n

3. Biblioteca ratelimit: enfoque minimalista

\n\n

ratelimit es la biblioteca más simple, que implementa una ventana deslizante con intervalos fijos. Es adecuada para escenarios sencillos donde no se necesita alta precisión.

\n\n

Ejemplo con ratelimit

\n
use ratelimit::Ratelimiter;\nuse std::time::Duration;\n\nfn main() {\n    let mut limiter = Ratelimiter::builder(10, Duration::from_secs(1))\n        .                    

Recommendations