Olha, a arquitetura que eu desenhei para o PIX foi pensada em três pilares não-negociáveis: nunca perder uma transação, manter latência abaixo de 200ms e escalar horizontalmente.
Eu organizei em quatro camadas:
Borda
A porta de entrada não deixa a requisição bater direto no core. Na frente, um load balancer distribui o tráfego. Essa camada cuida de autenticação, validação de contrato e proteção contra sobrecarga: rate limit por cliente e por API, além de throttling quando o sistema já está no limite. Também gera uma chave de idempotência para cada requisição — se o cliente mandar o mesmo PIX duas vezes, eu processo só uma.
Fila
Depois da validação, eu não processo na hora. Eu jogo para uma fila FIFO, com ordem garantida e exatamente-uma-vez. Se o banco ou o processador cair, a transação não se perde. Se a fila crescer demais, aplico backpressure: a borda reduz o aceite de novas requisições em vez de derrubar o core. E ainda tenho uma DLQ para isolar falhas sem travar o fluxo principal.
Core
Os workers são stateless e rodam em três zonas de disponibilidade diferentes. Se uma zona cair, as outras assumem. Eles consomem da fila e fazem validação de saldo com transação atômica. Para alta performance uso um banco NoSQL de chave-valor, particionado por ID do usuário para evitar hot partition. Já para extrato e auditoria, que precisam de consistência relacional, uso um banco relacional separado. Timeouts curtos em toda chamada externa evitam worker preso esperando para sempre.
Observabilidade
Cada request gera um correlation ID de ponta a ponta. Implemento retry com backoff exponencial e jitter, além de circuit breaker: se o serviço de saldo estiver instável, eu paro de chamar e devolvo erro rápido, evitando efeito cascata. Toda transação gera um evento imutável que vai para armazenamento de longo prazo, garantindo auditoria de cinco anos.
Escalabilidade
Sobre escalabilidade, eu nunca escalo verticalmente. Escalo horizontalmente: a borda cresce conforme número de requisições, os workers conforme tamanho da fila, e o banco de saldo conforme throughput. Isso me permite sair de 1k para 10k TPS sem mudar arquitetura, apenas adicionando instâncias.
No fim, o que eu garanto é simples: nenhuma transação perdida, nenhuma duplicada, o sistema se protege de sobrecarga com rate limit e, se qualquer parte quebrar, se recupera sozinho.