Marcio Cunha

Leaky Bucket vs Token Bucket: Guía Práctica de Control de Tráfico en APIs

Descubre cómo funcionan los algoritmos Leaky Bucket y Token Bucket en la gestión de tráfico de APIs. Entiende diferencias técnicas, ventajas y elige la mejor estrategia para proteger servidores.

Marcio Cunha12 min
También disponible en:EnglishPortuguês
Resumen
  • El algoritmo Leaky Bucket procesa solicitudes a velocidad constante, eliminando picos de tráfico repentinos para proteger servidores de sobrecargas.
  • El Token Bucket permite ráfagas controladas de acceso acumulando fichas con el tiempo, garantizando flexibilidad para aplicaciones modernas.
  • Elegir entre ambos enfoques depende directamente del perfil de uso, sopesando la tolerancia a ráfagas frente a la estabilidad estricta de procesamiento.
  • Los sistemas distribuidos exigen el uso de memorias rápidas como Redis para controlar los límites de tasa de manera centralizada y eficiente.
  • La correcta implementación del control de flujo previene ataques de denegación de servicio y asegura una distribución justa de recursos entre clientes.

El Desafío del Tráfico Imprevisible en las APIs

Imagina que gestionas la taquilla de un gran concierto. Miles de personas llegan al mismo tiempo a la entrada, creando una fila gigante y caótica. Si el personal deja pasar a todo el mundo de golpe, los torniquetes se rompen y la seguridad se compromete. Para resolver esto, los organizadores instalan barreras físicas que controlan el flujo, permitiendo el paso de un número seguro de personas por minuto. En el desarrollo de software, este problema ocurre constantemente cuando las aplicaciones reciben miles de accesos simultáneos.

Cuando una API (interfaz de programación de aplicaciones, el canal digital que permite la comunicación entre sistemas) sufre un pico repentino de tráfico, sus servidores pueden simplemente dejar de responder por falta de memoria o potencia de procesamiento. Para evitarlo, los ingenieros utilizan técnicas de control de flujo y limitación de tasa (rate limiting). Estos métodos actúan como las barreras de la taquilla, decidiendo quién entra de inmediato, quién va a una cola de espera y quién recibe un mensaje educado de que el sistema está lleno.

Existen varias formas de resolver este problema, pero dos destacan por su eficiencia y popularidad en la industria: Leaky Bucket (cubo con fugas) y Token Bucket (cubo de fichas). Cada uno posee una filosofía distinta sobre cómo gestionar el tiempo y los picos de acceso. Conocer a fondo el funcionamiento, las ventajas y los trade-offs (pérdidas y ganancias en una decisión de diseño) de ambas estrategias es fundamental para proyectar sistemas resilientes capaces de soportar fallas sin perder datos.

Cómo Funciona el Algoritmo Leaky Bucket en la Práctica

El concepto del Leaky Bucket es visualmente muy simple. Piensa en un cubo con un pequeño agujero en el fondo. No importa a qué velocidad eches agua dentro de ese cubo —ya sea vertiendo un vaso despacio o volcando un cubo entero de golpe—, el agua interior siempre escapará por el agujero inferior a un ritmo constante, gota a gota. En computación, el agua representa las solicitudes que llegan de los usuarios, el cubo es la cola de espera en la memoria y el agujero es la tasa fija de procesamiento.

En la práctica, cuando llega una nueva solicitud, se coloca en el cubo. Si el cubo está lleno —es decir, si la cola de espera alcanza su límite máximo—, las solicitudes entrantes se desbordan y se rechazan de inmediato con un error HTTP 429 (demasiadas solicitudes). Mientras tanto, el sistema extrae solicitudes del cubo para procesarlas a una velocidad constante e inmutable. Esto significa que, por más caótico que sea el tráfico externo, el servidor interno trabajará siempre a un ritmo tranquilo y previsible.

Esta característica hace que Leaky Bucket sea excelente para escenarios donde el destino final de las solicitudes tiene una capacidad de procesamiento rígida y no tolera oscilaciones. Por ejemplo, al enviar datos a una API de terceros con un límite estricto por segundo, Leaky Bucket garantiza que tu aplicación nunca viole ese límite porque la salida está estrictamente cronometrada. Lo negativo es su inflexibilidad: si un usuario legítimo necesita enviar diez solicitudes rápidas en un microsegundo, nueve se retrasarán o descartarán, aunque el servidor tenga capacidad ociosa temporal.

Entendiendo el Mecanismo del Token Bucket

A diferencia del cubo con fugas, el Token Bucket fue diseñado para abrazar la imprevisibilidad del comportamiento humano en internet. En este modelo, el cubo no almacena las solicitudes en sí, sino fichas (tokens) que otorgan el derecho de hacer una petición. Un proceso en segundo plano añade nuevas fichas al cubo a un ritmo constante, digamos, diez fichas por segundo. El cubo tiene una capacidad máxima; si está lleno, las fichas recién generadas simplemente se descartan.

Cuando un usuario realiza una solicitud a la API, el sistema comprueba si hay fichas disponibles en el cubo. Si las hay, se consume una ficha y la solicitud se procesa de inmediato. Si el cubo está vacío porque el usuario gastó todas las fichas de golpe, la solicitud se rechaza o se coloca en una cola de espera. En la práctica, esto significa que si un usuario pasa inactivo unos minutos, el cubo se llenará al máximo. Cuando regrese, podrá disparar varias solicitudes a la vez (una ráfaga), consumiendo todo el stock acumulado al instante.

Esta flexibilidad convierte a Token Bucket en la opción más popular para APIs públicas, portales de comercio electrónico y redes sociales. A los usuarios les encanta porque la navegación se siente fluida y rápida, sin bloqueos innecesarios durante acciones normales de múltiples clics. Para los ingenieros, el reto radica en dimensionar correctamente la capacidad máxima del cubo y la velocidad de reposición de fichas, asegurando que los picos legítimos se atiendan sin caídas de rendimiento en la infraestructura.

Comparación Directa: Trade-offs entre Leaky Bucket y Token Bucket

Para elegir el algoritmo ideal para tu proyecto, debemos comparar ambos y analizar sus comportamientos bajo distintas condiciones de estrés. La siguiente tabla resume las principales diferencias estructurales y operacionales entre ambos enfoques:

CriterioLeaky BucketToken Bucket
Tratamiento de PicosSuaviza completamente el tráfico, eliminando ráfagas de acceso.Permite ráfagas controladas hasta el límite del stock de fichas.
Uso de MemoriaAlmacena colas de solicitudes esperando procesamiento.Almacena solo contadores numéricos de fichas y marcas temporales.
PrevisibilidadExtremadamente previsible en la salida; ritmo quirúrgico.Variable en la salida según el patrón de consumo del cliente.
ComplejidadRequiere gestión de colas de espera y control estricto de temporizadores.Más sencillo de implementar usando operaciones atómicas en memoria.

En términos de consumo de recursos computacionales, Token Bucket suele ser más ligero para aplicaciones web de gran escala. Como no necesita guardar cada solicitud en una cola física, sino actualizar un entero (las fichas restantes), el coste de procesamiento por solicitud es mínimo. Leaky Bucket, en cambio, exige estructuras de datos de cola (arrays o listas enlazadas) que consumen más memoria RAM, especialmente cuando hay un gran volumen de conexiones esperando liberación.

Otro punto crítico es la experiencia del usuario final. Si estás construyendo una aplicación de chat o un panel financiero en tiempo real, Token Bucket ofrece una sensación de velocidad superior porque los paquetes cortos de datos pasan sin retrasos artificiales. Por otro lado, si integras sistemas heredados frágiles que colapsan con más de cincuenta peticiones por segundo, Leaky Bucket actúa como un escudo protector indispensable, nivelando el flujo de entrada e impidiendo sobrecargas catastróficas en la base de datos.

Implementando Límite de Tasa en Entornos Distribuidos

En la arquitectura de software moderna, rara vez ejecutamos una aplicación en un solo servidor. Los sistemas escalables usan múltiples nodos en paralelo equilibrados por un enrutador central. Esto crea un problema interesante para la limitación de tasa: ¿cómo controlas el cubo si las solicitudes de un mismo usuario llegan a servidores distintos? Si cada servidor mantiene su control aislado, el usuario burlará el límite redirigiendo llamadas entre instancias.

La solución estándar de mercado para este escenario es utilizar una base de datos en memoria de alto rendimiento, siendo Redis la opción más común. Redis permite almacenar el estado de las fichas de cada usuario de forma centralizada y accesible en milisegundos por cualquier servidor de la flota. Además, soporta operaciones atómicas y scripts ejecutados directamente en el servidor de base de datos (usando Lua), garantizando que dos solicitudes simultáneas no modifiquen incorrectamente el mismo cubo al mismo tiempo.

A continuación se muestra un ejemplo conceptual en código Python que demuestra la lógica de un Token Bucket usando una estructura simple en memoria, fácilmente adaptable para consultar Redis en un entorno distribuido:

import time

class TokenBucket:
    def __init__(self, capacity: int, refill_rate: float):
        self.capacity = capacity
        self.tokens = float(capacity)
        self.refill_rate = refill_rate
        self.last_refill = time.time()

    def _refill(self):
        now = time.time()
        elapsed = now - self.last_refill
        self.last_refill = now
        # Añade fichas según el tiempo transcurrido
        self.tokens = min(self.capacity, self.tokens + elapsed * self.refill_rate)

    def consume(self, tokens: int = 1) -> bool:
        self._refill()
        if self.tokens >= tokens:
            self.tokens -= tokens
            return True
        return False

# Ejemplo de uso
bucket = TokenBucket(capacity=10, refill_rate=2.0) # 10 fichas máx, repone 2 por segundo
if bucket.consume():
    print('¡Solicitud permitida!')
else:
    print('Demasiadas solicitudes. Inténtalo más tarde.')

En este código, la función _refill calcula exactamente cuántas fichas deben devolverse al cubo según el tiempo transcurrido desde la última comprobación. Este enfoque se conoce como cálculo por tiempo transcurrido (lazy refill), evitando mantener procesos en segundo plano ejecutándose constantemente para llenar el cubo.

Consideraciones Finales y Mejores Prácticas Operacionales

La elección entre Leaky Bucket y Token Bucket no debe tratarse como una decisión puramente técnica sin contexto de negocio. Refleja la promesa de servicio que tu API hace a los clientes. Mientras que Token Bucket prioriza la agilidad y la tolerancia a ráfagas de uso natural, Leaky Bucket prioriza la predictibilidad absoluta y la protección de recursos computacionales sensibles frente a picos destructivos de tráfico.

Al implementar estas estrategias en producción, recuerda siempre comunicar claramente los límites a los consumidores de tu API mediante cabeceras HTTP estandarizadas, como X-RateLimit-Limit, X-RateLimit-Remaining y X-RateLimit-Reset. Esto permite que los desarrolladores que consumen tu interfaz ajusten su software para respetar las reglas, evitando bloqueos frustrantes y mejorando la fiabilidad de todo el ecosistema tecnológico.