Otimização da resposta backend: filas, async, backpressure
1) Porquê: alvos e SLO
O objetivo é uma resposta rápida estável, mesmo sob os destaques. O negócio expressa isto SLO:- API (CRUD/diretório): p95 ≤ 250-400 ms, erro rate <1%.
- Pagamento/setlment (asincrona): SLA interno para confirmação de ≤ de 2-5 min e cliente de 202/Accepted + status-poller/webhook instantâneo.
- WS/real-time: RTT p95 ≤ 120 мс, disconnect ≤ 0. 5%.
A chave é desativar os passos «lentos» (provedores, banco de dados, APIs externas) da resposta do usuário através de filas e limitação de carga adequada.
2) Quadro básico: onde se encontra a latência
Pontos estreitos: BD (pula/índice), provedores externos (PSP/Jogos) que bloqueiam I/O, GC/Stop World, seriado JSON, agregações «pesadas».
Sintomas: p99, fila de conexões de BD, picos de retrações, tempo-outs cadeia (retry storm).
Antídoto: linha de montagem asincrona + backpressure + time-out/retrai + idempotação.
3) Patternos de asincrona: SEDA e CQRS
SEDA (staged event-driven arquiteture): divida o processamento em estágio (ingress → validação → gravação → integração → notificação). Cada uma tem fila e limites de paralelismo.
CQRS: divida leitura e gravação. A gravação é para o registro/base de dados, e a leitura é feita a partir de projeções/capas.
Outbox: evento é publicado atômico com a gravação (sem mensagens «perdidas»).
Saga: Processos de negócios longos com transações compensadoras em vez de transações globais.
4) Filas e striptease: escolha e sintonização
RabbitMQ/NATS JetStream - equipes de tarefas (work queues), Kafka - eventos/striptease com replay.
Configurações que afetam a resposta:- Prefetch/max in-flight: Limite o número de mensagens processadas simultaneamente por worker (por exemplo, 16-64) para não «marcar» o BD/API externo.
- Acker/repetições: 'ack' após a gravação idumpotente; repetições com atraso exponencial e jitter.
- DLQ/parking lot: não há retrações sem linha - depois de N tentativas de ir para Dead Better Queue.
- Partilhar (Kafka): chave por entidade (userId/txnId) para ordenar; paralelismo através do número de partituras.
5) Pressão inversa (backpressure) - como não afundar
A ideia é aceitar apenas o tempo que puder processar dentro da latência do SLO.
Técnicos:- Adesion control: limite a concorrência (semaphore/worker-pool) para cada dependência externa: BD, PSP, provedor de jogos.
- Shaping de tráfego: tocen-bucket/leaky-bucket na entrada do serviço e em rotas críticas.
- Filas de borda superior: ao preencher, corte a cauda (429/503 + Retry-After) ou transfira para asap-batch.
- Adaptativa concurrency (AIMD): Crie o paralelismo quando estiver bem sucedido, e reduza-o durante o tempo.
- Circuito Breaker: 'closed → open → half-open' por erros/tempo de API externo; em open - degradação (dinheiro/stab).
go sem: = make (chan estrutt se), por 64 )//limite de concorrência para o banco de dados/PSP
func handle(req) {
select {
case sem <- struct{}{}:
defer func(){ <-sem }()
ctx, cancel:= context. WithTimeout(req. ctx, 300time. Millisecond)
defer cancel()
res, err:= db. Do(ctx, req)
if err == context. DeadlineExceeded { metrics. Timeouts. Inc(); return TooSlow() }
return Ok(res)
default:
metrics. Backpressure. Inc()
return TooBusy(429, "Retry-After: 0. 2")
}
}6) Times-outs, retais e jitter: «Três baleias de sobrevivência»
Tempos mais curtos que o SLO: Se o SLO 400 ms, tempo para o BD/provedor 250-300 ms; tempo total de solicitação <400-600 ms.
Retraias limitadas e inteligentes: 1-2 tentativas max, apenas para operações seguras (idumpotentes), com exposição e jitter.
Coligação: agregue repetições para uma única chave.
Pseudocode (expoente + jitter):python for attempt in range(0, 2):
try:
return call(dep, timeout=0. 3)
except Timeout:
backoff = (0. 05 (2attempt)) + random. uniform(0, 0. 05)
sleep(backoff)
raise UpstreamUnavailable7) Idempotidade e dedução
Idempotency-Key em HTTP (depósitos, pagamentos), 'operation _ id' em banco de dados (índice único).
Inbox/Outbox: webhooks entrantes - sempre através de uma tabela inbox imutável com dedupe por 'evento _ id'; os saídos são de outbox por transação.
Exactly-once «no sentido»: Permitimos nova entrega/execução, mas o efeito é um só.
8) API rápida para operações lentas
Resposta sincronizada: 201/202 + URL de status ('/status/diante de '), ETA e dicas de retalho.
Webhooks/Server-Sent Events/WS - um poço de estágio quando pronto.
Disciplina do cliente: «Retry-After», Idempotidade, limite de pesquisa.
Exemplo de resposta:json
HTTP/1. 1 202 Accepted
Location: /v1/withdrawals/req_9f2/status
Retry-After: 2
{
"request_id": "req_9f2",  "state": "processing",  "next_check_sec": 2
}9) Minimizar o trabalho no caminho quente
Leve as coisas pesadas para o fundo, conversões, agregações, notificações, gravações em DWH.
Dinheiro e projeções: Muitas vezes lido - cachê-aside com TTL curto e deficiência de evento.
Batch Pattern: agrupe chamadas externas (por exemplo, solicitação de limites de provedor uma vez em N ms).
Serialização: codecs rápidos (protobuf/msgpack) para ligações entre servidores; O JSON está apenas no edge.
10) BD sob controle
Poulas de conexões: bordas superiores (com base em núcleos/IO), as filas de pool estão ativadas.
Índice e plano: p95 explain + auto de regressão de planos.
Os tempos de consulta são curtos, 'statement _ timeout' (Postgres).
Hot rows/locks: charding por chave, bloqueios otimistas (versão do balanço), saga em vez de transações «monolíticas».
11) WebSocket/real-time
Limitador de distribuição: batched broadcast, max msgs/sec per connect.
Backpressure interna: fila de mensagens de saída com gota; quando está cheio - drop low-priority.
Sticky-roting e PDB em lançamentos - para não gerar uma tempestade reconnect.
12) Observabilidade para não adivinhar
Métricas (RED/USE + backpressure):- 'request _ rate', 'erro _ ratio', 'latency _ p95/p99' nas rotas.
- `queue_depth`, `lag_seconds`, `consumer_inflight`, `retries_total`, `dlq_rate`.
- `backpressure_drops`, `admission_rejects`, `circuit_open`.
- Для БД: `connections_in_use/max`, `locks`, `slow_queries`.
- Trailers: span 'queue' worker db/psp 'com as marcas' operation _ id ',' partition ',' retry '.
- Logi: estrutural, com 'trace _ id', sem PII; eventos individuais «open/close circuito».
13) Testes sob carga
Open-model (arrivals/sec) para picos; O modelo Closed (VUs) para as sessões.
Perfis: breves burst 60-120 s e soak 1-4 h.
Injeções de falha: desacelere a API externa em + 200-500 ms, veja r99/retrai/filas.
Critérios de área verde: sem crescimento de 'queue _ lag', estável p95, 'dlq_rate≈0'.
14) Segurança e segurança
Filas de TLS/mTLS, assinatura de mensagens, controle de esquema (Avro/Protobuf + Schema Registry).
Idempotent producer (Kafka), exactly-once tx onde é justificado.
Modo de caos: «caia» o vício periodicamente e veja a degradação (circuito, fallback).
15) Exemplos de «pedaços» de configuração
Nginx/Envoy shaping de entrada:nginx limit_req_zone $binary_remote_addr zone=api:10m rate=20r/s;
server {
location /api/ {
limit_req zone=api burst=40 nodelay;
proxy_read_timeout 0. 6s; # SLO mais curto proxy _ connect _ timeout 0. 2s;
}
}
basic. qos (prefetch _ count = 32) # balanço CPU/IOjava props. put(ConsumerConfig. MAX_POLL_RECORDS_CONFIG, 200);
props. put(ConsumerConfig. FETCH_MAX_BYTES_CONFIG, 5_000_000);
props. put(ConsumerConfig. MAX_POLL_INTERVAL_MS_CONFIG, 60_000);16) Folha de cheque de implementação (prod-ready)
- Caminhos críticos divididos em resposta sincronizada e processamento asíncrono (SEDA).
- Admissão controle e limites de concorrência para dependências externas.
- Os times são mais curtos que o SLO; retrai ≤ 2, com exposição e jitter; Coligação.
- Circuito breaker + degradação (dinheiro/stab), política half-open.
- Filas/striptease: prefetch/in-flight, DLQ, partituras por chave.
- Idempotidade (operation _ id/Idempotency-Key), Outbox/Inbox, dedução.
- Dinheiro: cachê-aside, TTL curtos + deficiência de evento.
- BD: limites de pool, status _ timeout, índices, estratégias anti-lock.
- WS: limites de mensagens, batching, sticky-routing, pDB.
- Observabilidade: métricas backpressure/queues/retries, trailers end-to-end, dashboard.
- Testes de carga e falha (open + closed, burst + soak), critérios de área verde.
Currículos
Um backend rápido não é «fazer mais um dinheiro», mas um fluxo controlado: entrada limitada, pesada no fundo, cada etapa com filas e limites, retratos raros e inteligentes, e cadeias protegidas por circuito breaker e idimpotência. Adicione a disciplina de tempo, observação e testes regulares de estresse - e seus p95/p99 permanecerão verdes mesmo sob os buracos e caprichos de provedores externos.
