Planteamiento y contexto
Esta pregunta evalúa si "N solicitudes por minuto" puede transformarse en un plano de control y un plano de datos operables. Un limitador protege la capacidad a la vez que preserva la equidad y la prioridad del negocio; los nodos distribuidos y el estado compartido introducen aproximaciones. Cubre políticas, algoritmos, almacenamiento, respuestas, fallback, despliegue y métricas.
Qué evalúa el entrevistador
Las respuestas sólidas clarifican dimensiones, ventanas, ráfagas y semántica de fallas antes de comparar token bucket, leaky bucket, fixed window y sliding window. Separan la distribución de políticas de las decisiones en tiempo de solicitud, explican contadores atómicos, hot keys, comportamiento multirregión y fallas de Redis, y devuelven señales Retry-After accionables. También discuten despliegues en modo sombra (shadow rollout), presupuestos de error y excepciones auditadas.
Preguntas para clarificar
- ¿La clave es una API, tenant, usuario, IP o una combinación? ¿Se prioriza a los clientes premium?
- ¿Controlamos la tasa sostenida, el tamaño de la ráfaga, la concurrencia o varios recursos?
- ¿Una solicitud excedente falla, se encola, se degrada o recibe un pequeño margen adicional? ¿Se requiere consistencia global?
- Si el limitador no está disponible, ¿debe fallar en modo abierto (fail-open) o cerrado (fail-closed)? ¿Cuáles rutas son de alto riesgo?
- ¿Con qué frecuencia cambian las políticas y necesitamos despliegue gradual, auditoría, reversión (rollback) y efecto inmediato?
Estructura de respuesta en 30 segundos
“Separaría el control de políticas de las decisiones en tiempo de solicitud. Normalizaría el tenant, usuario y ruta en una clave; el plano de datos ejecuta un token bucket atómico en Redis Lua y devuelve la cuota restante y el tiempo de reintento. Las políticas versionadas se almacenan en caché, mientras que la caché local puede realizar rechazos rápidos, pero el estado compartido toma la decisión final. Durante una interrupción breve del almacenamiento compartido, las rutas de bajo riesgo usan un presupuesto de emergencia por tenant y fallan en modo abierto; las rutas de alto riesgo fallan en modo cerrado y envían alertas (page). El modo sombra, la tasa de consumo (burn rate), las métricas de hot keys y los límites de error regionales guían el despliegue.”
Respuesta detallada paso a paso
Paso 1: Definir capacidad y equidad
Separa la tasa sostenida, el tamaño de la ráfaga y la concurrencia. Las cuotas por tenant evitan que un solo cliente consuma el pool global; las cuotas por usuario contienen el ruido dentro de un tenant. Las rutas críticas pueden recibir presupuestos dedicados. La equidad es una política de negocio, no un comportamiento predeterminado accidental del algoritmo.
Paso 2: Elegir un algoritmo
Token bucket permite ráfagas controladas y se adapta bien a las API; leaky bucket suaviza la salida; las ventanas deslizantes (sliding windows) son intuitivas pero consumen más estado. Cuando el estado se comparte en Redis, usa TIME de Redis dentro del script atómico para que todos los nodos utilicen el mismo reloj, acota el tiempo transcurrido en cero y define la limpieza del estado y un límite de precisión.
Paso 3: Modelar claves y políticas
Normaliza método, ruta, tenant, principal y región para que los nodos deriven la misma clave. Una política incluye límite, ráfaga, alcance, prioridad, versión, tiempo de vigencia y propietario. Una política desconocida recurre a una línea base segura; los clientes no pueden proporcionar su propia cuota.
Paso 4: Hacer que la decisión sea atómica
Una sola operación compartida lee el estado, recarga tokens, descuenta el costo y actualiza el TTL. Redis Lua, una operación atómica de base de datos o un sidecar pueden funcionar; la clave es evitar condiciones de carrera de lectura y posterior escritura (read-then-write). Devuelve los tokens restantes, el tiempo de reinicio y la versión de la política.
Paso 5: Manejar hot keys y regiones
Un tenant popular puede convertir una clave en un punto caliente (hotspot). Divide (shard) su presupuesto y consolídalo en un coordinador solo si el margen de sobreuso es aceptable. Los sistemas multirregión pueden usar cuotas regionales y agregación global asíncrona; la consistencia global estricta penaliza la disponibilidad y la latencia.
Paso 6: Diseñar fallas y fallback
Elige fail-open o fail-closed según el riesgo de la ruta y establece un presupuesto de emergencia local. Cuando el almacenamiento de políticas no esté disponible, usa la última versión con un TTL corto. La recuperación no debe liberar toda la demanda acumulada de golpe. Audita cada excepción y decisión degradada.
Paso 7: Desplegar cambios
Ejecuta una nueva política en modo sombra primero, compara los rechazos proyectados y luego habilítala por tenant o por porcentaje. Incluye la versión de la política en los registros y mantén lista la reversión (rollback). Cada exención temporal necesita un propietario y una fecha de expiración.
Paso 8: Medir resultados
Monitorea la tasa de permisos/rechazos, la cuota restante, la latencia de decisión p95, las hot keys, los errores de almacenamiento, las versiones de políticas, las apelaciones por rechazos falsos y la sobrecarga del backend. Correlaciónalos con errores 5xx, profundidad de cola y latencia de cola (tail latency); limitar muy poco no protege, limitar demasiado perjudica al negocio.
Pseudocódigo de token-bucket atómico
now = redis_time()
state = load(key) or {tokens: burst, at: now}
elapsed = max(0, now - state.at)
state.tokens = min(burst, state.tokens + elapsed * rate)
allowed = state.tokens >= cost
if allowed:
state.tokens -= cost
state.at = now
save_atomically(key, state, ttl)
return allowed, state.tokens, retry_after(state)Compensaciones y límites
| Opción | Cuándo conviene | Costo principal |
|---|---|---|
| Token bucket | API con tráfico en ráfagas | Estado atómico compartido |
| Limitador local | Protección con la menor latencia | Cuota inexacta entre múltiples nodos |
| Cuotas regionales | Disponibilidad multirregión | Error en la equidad global |
| Fail-closed | Pagos y autenticación | Una caída del limitador afecta la disponibilidad |
La limitación de tasa (rate limiting) no es una cola ni un sustituto de la planificación de capacidad, circuit breaking o autenticación. Las colas son adecuadas para solicitudes que pueden esperar; un limitador rechaza rápidamente en el límite de un recurso en lugar de ocultar la sobrecarga como latencia.
Plan de despliegue y evidencia
Construye el modelo de políticas y el plano de datos de token-bucket para una API de alto volumen, ejecuta el modo sombra durante un día y luego habilítalo para unos pocos tenants. Microsoft Well-Architected trata la limitación de tasa como un control activo de sobrecarga; los materiales de DataInterview y System Design School enfatizan la elección del algoritmo, el estado compartido y Retry-After.
Criterios de salida de la prueba piloto
Tras simulacros de picos de tráfico, fallas del almacenamiento compartido, rollback y un tenant de alto tráfico, los objetivos de latencia aún se cumplen; cada rechazo falso tiene una causa justificada; los presupuestos de fallback funcionan; y las políticas tienen propietarios, versiones y registros de auditoría.
Cómo demostrar que la mejora es real
Compara sobrecargas del backend, errores 5xx, latencia p99, tasa de rechazo, tasa de falsos rechazos y costo de almacenamiento antes y después, segmentado por tenant, ruta y región. Normaliza según la capacidad para que un periodo natural de bajo tráfico no se confunda con el éxito.
Errores comunes y preguntas de seguimiento
Los contadores locales en cada nodo son suficientes
Cada nodo libera su propia cuota, por lo que un cliente puede exceder el límite cambiando de nodo. Cuantifica la aproximación o utiliza estado compartido/presupuestos regionales para rutas críticas.
Usar solo una ventana fija (fixed window)
Los límites de la ventana permiten una doble ráfaga breve. Utiliza token bucket o ventanas deslizantes y explica el costo de estado y la precisión.
Permitir el paso de todas las solicitudes cuando el limitador falla
Las rutas de alto riesgo pierden su última protección. Elige presupuestos de emergencia y fail-open/closed según el riesgo, con alertas (paging).
¿Cómo evitas perjudicar a los tenants premium?
Configura cuotas y prioridades por tenant, separa los pools compartidos y garantizados, y asigna a cada exención una fecha de expiración y un registro de auditoría.
¿Cómo deben reintentar los clientes?
Respeta Retry-After, utiliza retroceso con variación aleatoria (jittered backoff) y nunca reintentes un 429 indefinidamente. Los reintentos automáticos requieren solicitudes idempotentes.
¿Cómo realizas el despliegue canary de una nueva política?
Calcula en modo sombra, habilita por tenant o porcentaje, compara rechazos, conversión y carga del backend, y versiona la política para permitir rollback.