Rate Limits y control de carga
TL; DR
Un circuito fiable es una combinación de límites y cuotas en varios niveles (edge→BFF→servis), asignación equitativa de recursos (per-tenant/key/root), trottling adaptativo de SLO y retroceso en lugar de tiempos de espera silenciosos. Utilice token/leaky bucket para «velocidad», ventana deslizante para cuotas contables, límites competitivos para operaciones pesadas, trottling dinámico en degradación y circuit-breaker para apestrimes frágiles. Todo está bajo vigilancia y con playbucks.
1) ¿Por qué los límites en iGaming/fintech
SLO y resiliencia: protección contra avalanchas de retiros, picos de torneos/eventos, picos de pagos.
Justicia: un tenante o socio no «chupa» todo el presupuesto.
Antibugs/bots: inicio de sesión/registro, spam, scraping de directorios.
Costo: contención de llamadas costosas (KYC, informes, agregaciones).
Cumplimiento/uso de buena fe: cuotas formales «fair use» en los contratos.
2) Taxonomía de límites
3) Algoritmos y dónde aplicar
3. 1 Token Bucket (predeterminado)
Opciones: 'rate' (tokens/sec), 'burst' (stock max).
Excelente para API de lectura, pago/estado, BFF.
Con el backet vacío → 429 + 'Retry-After'.
3. 2 Leaky Bucket (promedio)
La «demolición» de RPS garantizada, es útil para que los webhooks no obstruyan los workers.
3. 3 Fixed Window vs Sliding Window
Fixed - simple, pero «límites»; Sliding - Contabilidad honesta en la ventana (min/hora/día).
Aplique Sliding para las cuotas contractuales.
3. 4 Concurrent Limits
Límite de tareas activas al mismo tiempo. Ideal para exportaciones/reportes, paquetes KYC, refrescos.
Con escasez - 429/503 + cola/polling.
3. 5 Cost/Complexity Limiter
GraphQL/búsqueda: contamos «costo» por profundidad/cardinalidad/extensiones.
Recorte/degradación de consultas «caras», respuesta con sugerencia.
4) Claves de límite (dimensioning)
per-tenant (alquiler múltiple, justicia),
per-api_key/client_id (socios),
per-route (las mutaciones críticas son más duras),
per-user/device/IP/ASN/geo (anti-bot/anti-scrape),
per-BIN/country (métodos de pago, protección de emisores y proveedores),
per-method (GET más suave, POST/PUT más estricto).
Composición: clave principal + «multiplicador de riesgo» (nueva cuenta, TOR/proxy, alto riesgo de chargeback).
5) Atornillamiento adaptativo de SLO
Active el trottling dinámico cuando SLO esté en peligro:- Desencadenantes: 'p95 latency↑', '5xx↑', 'queue len↑', 'CPU/IO saturation'.
- Acciones: bajar la tasa/burst, activar el outlier-ejection, cortar los routs «caros», degrade temporal (sin campos/agregaciones pesadas).
- Retorno: paso a paso (25→50→100%) cuando se normalizan las señales N de intervalos consecutivos.
6) Integración en la arquitectura
API Gateway (edge): rate/quotas primarios, geo/ASN, validación HMAC/JWT, 429/' Retry-After '.
BFF/Mesh Service: finos límites per-route/per-tenant, límites de concurrent, circuit-breakers a aptrims.
Dentro del servicio: semáforos para operaciones pesadas, retroexcavadora en colas, "pools' de trabajo con bound de tamaño.
Webhooks: un endpoint de ingress independiente con un bucket de leaky y un buffer de retrés.
7) Configuraciones (fragmentos)
Kong / NGINX-style (rate + burst):yaml plugins:
- name: rate-limiting config:
policy: local minute: 600 # 10 rps limit_by: consumer fault_tolerant: true
- name: response-ratelimiting config:
limits:
heavy: { minute: 60 }
Envoy (circuit + outlier + rate):
yaml circuit_breakers:
thresholds: { max_connections: 1000, max_requests: 800 }
outlier_detection:
consecutive_5xx: 5 interval: 5s base_ejection_time: 30s http_filters:
- name: envoy. filters. http. local_ratelimit typed_config:
token_bucket: { max_tokens: 100, tokens_per_fill: 100, fill_interval: 1s }
filter_enabled: { default_value: 100% }
filter_enforced: { default_value: 100% }
Concurrent-limits (pseudo):
pseudo sema = Semaphore(MAX_ACTIVE_EXPORTS_PER_TENANT)
if! sema. tryAcquire(timeout=100ms) then return 429 with retry_after=rand(1..5)s process()
sema. release()
GraphQL costa guard (idea):
pseudo cost = sum(weight(field) cardinality(arg))
if cost > tenant. budget then reject(429,"query too expensive")
8) Políticas para diferentes canales
REST
GET - más suave, POST/PATCH/DELETE - más estricto; los estados/comprobaciones «idempotentes» se pueden retractar.
Para pagos: límites en 'auth/capture/refund' per-user/tenant/BIN/país.
GraphQL
Depth/complexity caps, persisted/whitelisted queries, limites en «alias».
WebSocket/SSE
El límite de frecuencia 'subscribe/unsubscribe', el tope por número de topics, el control del tamaño de los eventos y la prueba de tamaño → cuando se desborda 'policy _ disconnect'.
Vebhuki
Bucket leaky en la recepción, cuotas per-sender, cola dead-letter, determinista 2xx/429.
9) Comentarios a los clientes
Siempre devuelva un claro 429 con los titulares:- `Retry-After:
` - `X-RateLimit-Limit/Remaining/Reset`
- Para las cuotas, 403 con el código 'quota _ exceeded' y una referencia a la actualización del plan.
- Documentación: límites en OpenAPI/SDL + página «Uso justo».
10) Monitoreo y dashboards
Métricas:- Hits Limits: 'rate. limit. hit 'por claves/routs/tenantes.
- 429/503 доля, latency p50/p95/p99, error rate, queue length, open circuits.
- Fair-share: los mejores tenantes en consumo, el «detector bully».
- Webhooks: recepción/retraídas, drop-rate, media de la regla.
- 429 no más del 1-3% del RPS total (sin bots).
- p95 aditivo limitador ≤ 5-10 ms en edge.
- Tiempo de recuperación después de la degradación ≤ 10 minutos.
sql
SELECT ts::date d, tenant, route,
SUM(hits) AS limit_hits,
SUM(total) AS total_calls,
SUM(hits)::decimal/NULLIF(SUM(total),0) AS hit_rate
FROM ratelimit_stats
GROUP BY 1,2,3
ORDER BY d DESC, hit_rate DESC;
11) Playbucks de incidentes
Tormenta de retraídas (caída de apstream): habilitar el trottling global, levantar el backoff, abrir el circuit-breaker, devolver los «errores rápidos» en lugar de los tiempos de espera.
Bot Attack/Scraping: tope duro por IP/ASN/geo, habilite el desafío WAF/JS, limite directorios/búsqueda.
Pico del torneo/eventa: elevar preventivamente los límites de lectura, reducir los «campos caros», incluir caché/desnormalización.
Desahogo de webhooks del PSP: bucket de leaky temporal, priorizar tipos críticos, ampliar el dead-letter y retraer.
12) Pruebas y UAT
Carga: RPS por la escalera, bursts × 10 de normal.
Justicia: emulación de 1 tenante «codicioso» - no más de X% del presupuesto global.
Degradación: La adaptación SLO reduce los límites y mantiene p95 en el pasillo.
Casos de límite: cambio de ventana (min→chas), temblor de reloj (clock skew), escalado de Redis/charding de llaves.
Contrato: los títulos 429 y Retry-After están presentes, SDK correctamente back-offit.
13) Almacenamiento para límites
En memoria para los límites locales (clústeres pequeños).
Redis/Memcached para distribuidos (scripts de Lua para atomicidad).
Charding de llaves por hash; TTL debajo de las ventanas; backup métrica para la pérdida de caché.
Idempotencia: el limitador no debe romper las llamadas repetidas idempotentes (contabilidad por clave de solicitud).
14) Administración de políticas (Governance)
Catálogo de límites: quién es el propietario, qué claves/umbral/racionado.
Características-flags para interruptores rápidos (modo de crisis).
Versionar las políticas y el proceso RFC para modificar las cuotas contractuales.
Experimentos A/B para la selección de umbrales óptimos.
15) Anti-patrones
Un límite global «para todas las API».
Sólo ventanas fijas → saltos de «borde».
Límite sin retroalimentación (sin 'Retry-After '/headers).
Tiempos silenciosos en lugar de rápidos 429/503.
Falta de fair-share per-tenant: un cliente estrangula al resto.
No hay protección GraphQL/búsqueda por complejidad.
Los ceros en la guardia concursal → la «aspiradora» de la DAB/PSP.
16) Selección de mini parche
Por defecto: token bucket (rate + burst) per-tenant + route.
Cuotas de dinero/informes: sliding window día/mes.
Operaciones pesadas: concurrent-limits + cola.
GraphQL/поиск: complexity-budgets + persisted queries.
WS/webhooks: leaky bucket + backpressure.
Кризис: dynamic throttling + circuit-breaker + degrade.
Resumen
El control de carga es una disciplina de varios niveles: algoritmos correctos (bucket/windows/competition), llaves de límite justo, adaptación SLO y retroalimentación transparente. Al meter los límites en gateway/mesh/services, armar GraphQL/WS/webhooks con pólizas de perfil y conectar la vigilancia con los playbooks, convierte los eventos máximos y las fallas de otras personas en situaciones manejables, sin troceos, pagos frustrados y reducciones de conversión.