Diseño de rate limiter's
1) Por qué rate limiting
Rate limiting protege la disponibilidad y la economía de la API: detiene floods, «burst» de retiros, credential stuffing, protege operaciones costosas (transacciones monetarias, generación de informes), suaviza la carga sobre los sistemas dependientes (DB/proveedores). Un buen diseño da justicia (fairness), predecibilidad de latencia y un SLO claro.
Objetivos clave
Estabilidad de RPS y protección contra sobrecarga de respaldo.
Elasticidad controlada (burst allowance).
Diferenciación de clientes (per-usuario/per-organización/per-llave/per-IP/per-región).
Modelo de valor: diferentes «precios» para diferentes operaciones.
2) Tipos de límites
Límites RPS: solicitudes por segundo/minuto.
Cuotas: presupuesto total durante el período (día/mes).
Competitividad: operaciones simultáneas (checkout, heavy job).
Velocidad/banda: bytes/segundos (carga/descarga).
Límites ponderados: «costo» de una consulta por complejidad (por ejemplo, complexity GraphQL, tamaño de batch).
Adaptativo: se endurecen en anomalías (actividad sospechosa/errores 401/403/5xx).
3) Algoritmos y cuándo aplicarlos
3. 1 Fixed window counter
Simple: contador por intervalo (por ejemplo, 100 r/min).
Pros: costo mínimo. Contras: «bordes» en los límites de la ventana.
Cuándo: panel del almirante, precisión baja, bajo costo.
3. 2 Sliding window (log / counter)
Registro: almacena las marcas de tiempo de las últimas solicitudes, exactas, de los caminos de memoria.
Counter: media de dos ventanas adyacentes (rolling), compromiso de precisión y precio.
Cuándo: API públicas de tráfico medio, necesita fluidez sin matemáticas complejas.
3. 3 Token bucket
Opciones: velocidad 'r' (tokens/sec) y capacidad 'b' (burst). Cada solicitud «quema» el token.
Pros: natural burst allowance, implementación simple. Contras: no hay uniformidad estricta.
Cuándo: casi siempre para RPS si se necesitan «volteretas» dentro de 'b'.
3. 4 Leaky bucket (drip)
Cola de la que se «filtra» a una velocidad fija.
Ventajas: flujo de salida uniforme. Contras: más retrasos.
Cuándo: suavizar a proveedores externos «frágiles».
3. 5 GCRA (Generalized Cell Rate Algorithm)
Modelo de tiempo teórico de llegada (TAT):- 'TAT _ next = max (TAT_current, ahora) + 1/r', la solicitud es aceptada si 'now <= TAT_current + burst/r'.
- Pros: riguroso, preciso, poca memoria (almacenamos TAT en clave). Contras: más difícil de entender.
Cuándo: necesita un control estricto y suavidad, límites distribuidos.
3. 6 semáforos competitivos
Contador de operaciones activas; entrada - si hay «entradas»; salida - liberación.
Cuándo: operaciones long-running, hilos, WebSocket, descargas.
4) Modelo de claves de límite
Clave = combinación de atributos:- `client_id`/`api_key`/`user_id`/`org_id`
- 'IP/ASN/geo' (defensa en bruto)
- 'endpoint/method' (rutas calientes)
- 'scope/plan/tier' (monetización)
- 'idempotency _ key' (operaciones de escritura)
- Use la jerarquía: primero la llave PE estricta, luego la organización PE, luego la global.
5) Peso de la consulta (modelo de costo)
Definir el «costo» de 'costo (q)':- GraphQL: complejidad por campos × profundidad.
- NAT: tamaño de respuesta/consulta, tipo de operación (read = 1, write = 3, informe = 10).
- Batch: `cost = min(n, cap)`.
- Limitamos los tokens, no las «consultas»: 'budget - = costo (q)'.
6) Implementación distribuida
6. 1 Almacenamiento
In-process: ultra-rápido, pero no el límite total (adecuado para los límites «blandos» locales).
Redis: estándar de facto. INCR/EXPIRE, scripts Lua (atomicidad), ZSET para ventana deslizante, claves con TTL.
Envoy/NGINX/Kong/Traefik: filtros integrados; conveniente para el perímetro.
Mesh de servicio: límites locales para sidecar + sincronización global.
6. 2 Atomicidad y carreras
Lua en Redis: verificación e incremento en un solo paso.
GCRA: almacenar un TAT con CAS/script.
Consistencia del reloj: NTP, temporizadores monótonos.
Sharding: hash consistente por clave; evite los chardos «calientes».
6. 3 Distribución geográfica
Límites locales en clústeres regionales + global superior (coarse).
CRDT/replicación - precaución (latencia, doble flujo). Los límites regionales con existencias son preferibles.
7) Políticas y prioridades
Planes: Free/Pro/Enterprise con diferentes 'r', 'b', cuotas.
Prioridades: las rutas «caras» obtienen un límite menor o un costo mayor.
Listas: allow-list para integraciones, deny por ASN/proxy/TOR.
Escalada: si se vuelve a superar, rebaje el límite, introduzca proof-of-work/captcha/challenge.
8) Ejemplos de confecciones
8. 1 Envoy (HTTP rate limit filter, pseudo)
yaml rate_limit:
domain: public-api descriptors:
- key: api_key rate_limit:
unit: second requests_per_unit: 50 burst: 100
- key: api_key value: payments. write rate_limit:
unit: second requests_per_unit: 5 burst: 10
8. 2 NGINX (lua + Redis, pseudo)
nginx lua_shared_dict limits 10m;
location /api/ {
access_by_lua_block {
local key = ngx. var. arg_apikey.. ":".. ngx. var. request_method.. ":".. ngx. var. uri
-- token bucket in Redis (evalsha)
local allowed, retry_after = ratelimit_allow(key, 50, 100) -- r=50/s, b=100 if not allowed then ngx. header["Retry-After"] = retry_after return ngx. exit(429)
end
}
proxy_pass http://backend;
}
8. 3 Límites competitivos (pseudocódigo)
pseudo on_request_start(key):
if redis. incr_with_ttl("sem:" + key, ttl=60) > MAX_CONCURRENCY:
redis. decr("sem:" + key); reject(429)
on_request_finish(key):
redis. decr("sem:" + key)
8. 4 GCRA (pseudocódigo)
pseudo params: r tokens/sec, burst b tat = redis. get(key) or now allowed_time = tat - (b / r)
if now < allowed_time: reject(429, retry_after = allowed_time - now)
tat_next = max(tat, now) + 1/r redis. set(key, tat_next, ttl = ceil(b/r) + safety)
9) Integración con retraídas, temporizadores y circuitos breaker
Retry-budget: limite la proporción de retraídas a X% del tráfico principal.
Jitter: cuando el backoff siempre agrega un jitter - reduce las ráfagas sincrónicas.
Circuit breaker: con una alta falacia ('5xx', timeouts), reduce los límites o traduce parte de las rutas a 'read-only'.
Hedging: suavemente; tenga en cuenta el costo para no duplicar el gasto del presupuesto.
10) Observabilidad y gestión
Метрики: `rps_allowed`, `rps_blocked`, `429_rate`, `retry_after_avg`, `burst_used`, `quota_remaining`, `active_concurrency`.
Etiquetas: por clave de límite, región, endpoint, plan.
Registros de soluciones (sampleados): causa de fallo, contadores actuales, llaves TTL.
Dashboards: tarjetas térmicas por llaves/endpoints, clientes «calientes».
Alertas: crecimiento de 429> 2-5% en rutas críticas, frecuentes «agotamientos» de cuotas, desequilibrios de chardos.
11) Pruebas y validación
Pruebas contractuales de políticas (tablas «si hay algo»).
Carga: burst (x10 de r), mesetas largas, patrones «sucios» (slow-POST, conexiones largas).
Tráfico de chaos: flujos desiguales, clock drift, Redis/mesh.
A/B-habilitación: canary rollout limites, shadow-solutions (lógica, pero no bloqueamos) antes de habilitar.
12) Casos de edge y sutilezas
Clock skew: utilice 'now ()' desde una sola fuente (servidor), no desde los encabezados del cliente.
Idempotency-Key: para escribir: reduce la amplificación en los retratos.
Operaciones de batalla: limite el tamaño del batch y el costo total.
Long-poll/WebSocket: limite el número de canales/suscripciones y la duración.
Inicio frío: inicio «cálido» de los contadores/precarga; de lo contrario, picos de 429 falsos.
Consultas computacionalmente costosas: limite hasta que se ejecute la lógica empresarial.
Bordes TTL: las llaves TTL deben cubrir la ventana + stock (margen de seguridad).
13) Escalamiento antibot
Pasos: advertencia → 429 + 'Retry-After' → challenge (capcha/rompecabezas) → unidad temporal.
Señales: device-fingerprint, comportamiento del cursor/timing, TOR/proxy/hosting.
Los políticos deben ser deterministas y reproducibles para los forenziques.
14) Seguridad y cumplimiento
Deny-by-default en rutas críticas (escritura/finanzas).
Auditoría: mantenga las soluciones de límites para casos regulatorios y análisis de incidentes.
PII: las claves de límite no deben revelar datos personales en los logs.
15) Lista de comprobación prod
- Se han definido las claves de límite y el modelo de costo.
- Se seleccionó el algoritmo (token bucket/GCRA) y el repositorio (Redis/gateway).
- Políticas para clientes tier's + «fusibles» globales.
- Límites competitivos para operaciones largas.
- Retry-budget, backoff con jitter, integración con circuit breaker.
- Dashboards/alertas, registros de soluciones sampleadas.
- Canary-encendido y modo shadow.
- Pruebas de burst, mesetas de larga duración, fallos de Redis, clock skew.
- Documentación para clientes: códigos 429, 'Retry-After', ejemplos de backoff exponencial.
16) TL; DR
Utilice el bucket token o el GCRA con Redis/gateway, diseñe las claves de límites y el costo de las consultas, agregue semáforos competitivos para operaciones largas, integre con retry-budget y circuit breaker, observe el 429 y la «capacidad burst», desenrolle límites a través de canary/shadow y asegúrese de probar bursts y fallos de almacenamiento.