Publicado · en mejora
Algorithm
La limitación de tasa restringe las peticiones por usuario o IP en cada ventana de tiempo: token bucket, ventana deslizante, leaky bucket y Redis.
Un limitador de tasa (rate limiter) controla cuántas peticiones se aceptan en un periodo de tiempo. Se define una clave, un límite y una ventana, por ejemplo "100 peticiones por minuto por usuario", y lo que supere ese límite se rechaza o se retrasa. Los algoritmos clásicos son ventana fija, registro de ventana deslizante, contador de ventana deslizante, token bucket y leaky bucket, y se diferencian en precisión, memoria y manejo de ráfagas.
Casi cualquier función expuesta al exterior, desde las API públicas hasta el inicio de sesión, los pagos o el envío de mensajes, está detrás de un limitador de tasa. Protege a los servidores de picos de tráfico y de bucles de reintentos descontrolados, evita que un usuario acapare la capacidad compartida y frena los ataques de fuerza bruta. También es un tema habitual en las entrevistas de diseño de sistemas.
Empieza escribiendo un contador de ventana fija y comprueba cómo deja pasar el doble del límite en el borde de la ventana; después corrígelo con una ventana deslizante y un token bucket. Luego aprende a probar con un reloj inyectado, a responder HTTP 429 con Retry-After y a compartir un límite entre servidores con INCR, EXPIRE y scripts Lua de Redis.
Los tokens se reponen a ritmo constante y cada petición gasta uno: se respeta una tasa media y se permiten ráfagas hasta la capacidad del cubo.
Un registro de marcas de tiempo, o una mezcla ponderada de dos contadores, cuenta las peticiones recientes sin el pico en el borde de la ventana fija.
Límites separados por ID de usuario, clave de API, IP o endpoint impiden que un solo cliente acapare los recursos.
El INCR atómico de Redis y los scripts Lua permiten que muchos servidores compartan un límite sin condiciones de carrera.
TokenBucket repone rate tokens por segundo y guarda como máximo capacity. allow() suma de una vez los tokens ganados desde la última llamada (reposición perezosa) y gasta uno si hay suficientes. Al ejecutarlo, las 5 primeras llamadas pasan como ráfaga y las 3 siguientes se rechazan; tras una pausa de 1,1 segundos pasan otras dos. El tiempo se mide con time.monotonic(), que nunca retrocede.
token_bucket.py
import time
class TokenBucket:
"""Allow bursts of up to `capacity` requests, refilled at `rate` tokens per second."""
def __init__(self, rate: float, capacity: float) -> None:
self.rate = rate
self.capacity = capacity
self.tokens = capacity
self.updated = time.monotonic()
def allow(self, cost: float = 1.0) -> bool:
now = time.monotonic()
self.tokens = min(self.capacity, self.tokens + (now - self.updated) * self.rate)
self.updated = now
if self.tokens >= cost:
self.tokens -= cost
return True
return False
if __name__ == "__main__":
bucket = TokenBucket(rate=2, capacity=5) # 2 requests per second, bursts of 5
print([bucket.allow() for _ in range(8)]) # 5 x True, then 3 x False
time.sleep(1.1) # about 2.2 tokens come back
print(bucket.allow(), bucket.allow(), bucket.allow()) # True True False
python token_bucket.pySeis capítulos que te llevan desde la instalación hasta las ideas clave de Limitación de tasa.
Haz preguntas, comparte tu experiencia e intercambia opiniones sobre Limitación de tasa.
Todavía no hay debates. Empieza el primero.
0 comentarios
Iniciar sesión · Inicia sesión para dejar un comentario.
Sé el primero en comentar.