Rate Limits e controle de carga
TL; DR
Um circuito confiável é uma combinação de limites e quotas em vários níveis (edge→BFF→servis), distribuição justa de recursos (per-tenant/chave/rout), trottling adaptativo SLO e backprescher em vez de temporais silenciosos. Use tocen/leaky bucket para «velocidade», janela deslizante para quotas contábeis, limites competitivos para operações pesadas, dinamic throttling para degradação e circuito-breaker para upstream frágeis. Tudo sob observabilidade e playbooks.
1) Por que os limites de iGaming/fintech
SLO e sustentabilidade: proteção contra avalanches de retrações, picos de torneios/events, saltos de pagamento.
Justiça, um tenente ou sócio não «suga» todo o orçamento.
Antiabws/bots: personalização de login/registro, spam, diretórios de screeping.
Custo: contenção de chamadas caras (KYC, relatórios, agregações).
Complacência/boa-fé: quotas formais «fair use» em contratos.
2) Taxonomia de limites
3) Algoritmos e onde aplicar
3. 1 Token Bucket (padrão)
Parâmetros: 'rate' (tokens/segundos), 'burst' (reserva máxima).
Excelente para API read, pagamento/estatais, BFF.
Com o baquete vazio, 429 + 'Retry-After'.
3. 2 Leaky Bucket (média)
«Demolir» RPS garantido, útil para os webhooks para não marcar os workers.
3. 3 Fixed Window vs Sliding Window
Fixed - simples, mas «limites»; Sliding - contabilidade justa na janela (min/hora/dia).
Use o Sliding para quotas contratuais.
3. 4 Concurrent Limits
Limite de tarefas ativas simultaneamente. Ideal para exportação/reposição, pacotes KYC, reaproveitamento.
Quando a escassez é 429/503 + fila/polling.
3. 5 Cost/Complexity Limiter
GraphQL/pesquisa: Consideramos o «custo» em profundidade/radicalidade/extensões.
Corte/degradação de consultas «caras», resposta com uma dica.
4) Chaves de limitação (dimensioning)
per-tenant (multiarenda, justiça),
per-api _ key/cliente _ id (parceiros),
per-road (mutações críticas mais severas),
per-user/device/IP/ASN/geo (antibot/anticrape),
PER-BIN/country (métodos de pagamento, proteção de emissores e provedores),
per-method (GET mais suave, POST/PUT mais rigoroso).
Composição: chave principal + «multiplicador de risco» (nova conta, TOR/proxy, alto risco chargeback).
5) Trottling adaptativo SLO
Ative a dinamic throttling quando o SLO estiver em perigo:- «p95 latency↑», «5xx↑», «queue len↑», «CPU/IO saturation».
- Ações: rebaixar rate/burst, incluir outlyer-ejation, cortar «caros» routs, degrade temporária (sem campos pesados/agregações).
- Retorno: estágio (25→50→100%) na normalização dos sinais N de intervalos consecutivos.
6) Integração na arquitetura
API Gateway (edge): rate/cotas primárias, geo/ASN, HMAC/JWT-validação, 429/' Retry-After '.
BFF/Service Mesh: Finos per-road/per-tenant limites, concurrent-limits, circuito-breakers para upstream.
Dentro do serviço: semaforas para operações pesadas, backpreser nas filas, «balas de trabalho» com tamanho bound.
Webhooks: endpoint personalizado com leaky bucket e buffer de retrações.
7) Configurações (fatias)
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 a costa guard (ideia):
pseudo cost = sum(weight(field) cardinality(arg))
if cost > tenant. budget then reject(429,"query too expensive")
8) Políticas para diferentes canais
REST
GET - mais suave, POST/PATCH/DELETE - mais rigoroso; estatais/verificações «idepartidas» podem ser retransmitidas.
Para pagamentos: limites para 'auth/capture/refund' per-user/tenant/BIN/país.
GraphQL
Depth/complexity caps, persisted/whitelisted qualies, limites para «alias».
WebSocket/SSE
Limite de frequência 'subscribe/unsubscribe', kap por número de topics, controle de tamanho de evento e send-queue → quando o 'policy _ disconnect' está cheio.
Webhooks
Leaky bucket na recepção, per-sender quotas, dead-better fila, determinados 2xx/429.
9) Feedback aos clientes
Devolva sempre um 429 claro com títulos:- `Retry-After:
` - `X-RateLimit-Limit/Remaining/Reset`
- Para quotas, 403 com código 'quota _ exceeded' e referência ao upgrade do plano.
- Documentação: limites na página «Fair Use» +.
10) Monitoramento e dashboards
Métricas:- Os hits de limite são 'rate. limit. hit 'por chaves/rotas/tenantes.
- 429/503 доля, latency p50/p95/p99, error rate, queue length, open circuits.
- Fair share: top tenentes de consumo, «bully detector».
- Webhooks: recepção/retrai, drop-rate, liga média.
- 429, no máximo, 1-3% do RPS total (sem bots).
- p95 suplemento de limite ≤ 5-10 ms por edge.
- Tempo de recuperação da degradação ≤ 10 min.
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) Playbooks incidentes
Tempestade de retrações (queda de upstream): ativar o global throttling, levantar backoff, abrir o circuito-breaker, recuperar «erros rápidos» em vez de times-out.
Bot-ataque/screaping: rígido por IP/ASN/geo, incluir WAF/JS-challenge, limitar diretórios/busca.
Pico do torneio/eventa: elevar preventivamente os limites de leitura, reduzir «campos caros», incluir kesh/denormização.
Leaky bucket temporário, priorização de tipos críticos, ampliação de dead-letter e retrai.
12) Testes e UAT
Carga: escada RPS, burst x 10 do normal.
Justiça: Emulação 1 tenente «ganancioso» - não mais do que X% do orçamento global.
Degradação: Adaptação SLO reduz limites e mantém p95 no corredor.
Mala de limite: mudança de janela (min→chas), tremores de relógio (clock skew), escala Redis/Charding chaves.
Contrato: títulos 429 e Retry-After estão presentes, SDK correto back-off.
13) Armazenamento para limites
In-memory para limites locais (pequenos clusters).
Redis/Memcached para links para atomalidade.
Charding de chaves por hash; TTL sob as janelas; bacap-métrico para perder o dinheiro.
Idempotency: O limitador não deve quebrar as chamadas idempotativas (contabilidade por chave de solicitação).
14) Gerenciamento de políticas (Governance)
Catálogo de limites: quem é o dono, quais chaves/limiar/racional.
Função-flags para botões rápidos.
Versionização de políticas e processo RFC para alterações nas quotas contratuais.
A/B experimentos para definir liminares ideais.
15) Anti-pattern
Um limite global para todas as APIs.
Apenas janelas fixas → corridas de borda.
Limite sem feedback (nenhum 'Retry-After '/headers').
Times silenciosos em vez de rápidos 429/503.
Falta de per-tenant fair-share - um cliente sufoca os outros.
Não há proteção do GraphQL/Pesquisa por complexidade.
Zero em concurrent-guard → «aspirador» BD/PSP.
16) Mini-caixa de seleção
Por padrão: tocen bucket (rate + burst) per-tenant + rota.
Quotas de dinheiro/relatório: sliding window dia/mês.
Operações pesadas: concurrent-limits + fila.
GraphQL/поиск: complexity-budgets + persisted queries.
WS/webhooks: leaky bucket + backpressure.
Кризис: dynamic throttling + circuit-breaker + degrade.
Currículo
O controle de carga é uma disciplina de vários níveis: algoritmos corretos (bucket/janelas/concorrência), chaves de restrição justas, adaptação SLO e feedback transparente. Ao colocar limites em gateway/mesh/serviços, armar o GraphQL/WS/webhooks com pólis de perfil e ligar a observabilidade com playbooks, você transforma eventos de pico e falhas alheias em situações controláveis - sem cargas, pagamentos quebrados e falhas de conversão.