O problema: seu load balancer não foi feito para conversas
APIs web tradicionais têm um ciclo de vida lindo e previsível: cliente manda request, servidor responde, conexão fecha. Você mede latência, QPS, CPU — tudo cabe bonitinho num dashboard. 🎯
Agora coloca um agente de IA em tempo real nesse cenário. Em vez de requests isolados, seu backend passa a gerenciar streams bidirecionais contínuos — chunks de áudio, transcrições parciais, saídas do modelo e fala sintetizada fluindo tudo ao mesmo tempo. Quando o usuário interrompe no meio da frase, o servidor precisa parar a geração, atualizar o contexto, talvez disparar uma tool call nova e começar a rascunhar outra resposta — sem derrubar a conexão. 😅
Isso não é mais um problema de rede. É um problema de estado na camada de aplicação, e load balancers genéricos simplesmente não enxergam isso.
📎 Essa análise aprofunda os padrões de infraestrutura discutidos no deep dive original de engenharia.
![]()
Por que QPS e CPU sozinhos vão te trair
Imagina duas tasks no mesmo backend:
- Task A: recebe 100 requests curtos, cada um terminando em 50ms.
- Task B: aceita só 5 requests, mas cada um vira uma sessão de 20 minutos.
Pela taxa de chegada, a Task B parece ociosa. Na real, tá carregando um workload comprometido MUITO mais pesado. Esse é o modo de falha clássico do balanceamento baseado em request para IA em tempo real.
CPU é igualmente traiçoeiro. Um runtime de voz pode hospedar 20 sessões silenciosas sem inferência rolando — o servidor parece subutilizado. No segundo em que os 20 usuários começam a falar juntos, o CPU explode e o balancer entra em pânico. 💥
A solução: rastrear sessões na camada de aplicação
O backend é o único componente com contexto suficiente pra saber quando uma sessão está realmente ativa versus falhada, finalizada ou cancelada. Olha o padrão mínimo em Kotlin com coroutines:
suspend fun handleAudioSession(audioStream: Flow) {
activeSessions.incrementAndGet()
try {
withTimeout(20.minutes) {
audioStream.collect { frame ->
processAndRespond(frame)
}
}
} finally {
// O bloco finally é o que mantém a contagem de sessões ativas
// precisa o suficiente para decisões de roteamento.
activeSessions.decrementAndGet()
}
}
Se esse contador não decrementar, seu backend parece sobrecarregado muito depois da sessão acabar. Decrementa duas vezes e você reporta capacidade falsa, atraindo tráfego que não consegue atender. Em produção, você precisa tratar o caso chato onde timeout, cancelamento e disconnect disparam ao mesmo tempo na mesma sessão. 😵
De slots estáticos para um modelo híbrido
Um modelo ingênuo de capacidade é assim:
remaining_capacity = max_sessions - active_sessions
Se você tem espaço pra 100 sessões e 80 estão ativas, sobram 20 slots. Simples — e frágil. Ele assume que toda sessão custa o mesmo CPU, o que nunca é verdade em IA generativa.
O caminho certo é um modelo híbrido que mistura utilização (pressão atual) com contagem de sessões (carga futura já comprometida). Load balancers pensam em taxas, então converta contagens estáticas em fluxo contínuo. Se um backend segura 90 sessões ativas numa janela de 10 segundos, trata isso como 9 "QPS de mentirinha". Agora a pressão de sessão entra direto na sua matemática de roteamento. 🧮
O princípio: um load balancer de IA em tempo real precisa entender tanto o peso do estado atual quanto o volume de sessões comprometidas.

Validando o sistema sem mentir pra si mesmo
Teste de carga fire-and-forget não serve aqui. Rajadas de requests curtos medem throughput, não o comportamento de sessões longas de IA. Seus benchmarks precisam variar:
- Duração da sessão (30s vs. 20min)
- Frequência de interrupção (ouvintes silenciosos vs. bate-volta rápido)
- Rampa de concorrência (crescimento gradual vs. manada trovejante)
Métricas que realmente importam
Além de latência média e QPS, rastreie:
- Distribuição de sessões ativas entre backends
- Taxas de atribuição sobrecarregada
- Latência de startup p95 e p99
- Time-to-first-stream
- Sessões dropadas
- Comportamento do contador após disconnects forçados
O custo escondido: contenção no contador
Todo início e fim de stream bate no seu tracker de sessões. Em concorrência massiva, esse tracker fica no critical path. Pra serviços JVM, isso significa microbenchmark de verdade com JMH — considerando warmup da JIT e eliminação de dead-code que distorcem resultados ingênuos.
Aqui está a armadilha que pega a maioria dos times: um AtomicInteger parece ok no papel, mas sob alta concorrência sofre cache-line bouncing conforme múltiplas threads martelam o mesmo endereço de memória. Em cenários de alto throughput, considere sharded counters ou agregação estilo LongAdder.
// Ingênuo — sofre contenção de cache-line sob carga
AtomicInteger activeSessions = new AtomicInteger(0);
// Melhor — LongAdder espalha as escritas entre células
LongAdder activeSessions = new LongAdder();
activeSessions.increment();
long current = activeSessions.sum();
⚠️ Limitações e cuidados
- Modelos híbridos exigem tuning. As constantes de
Safety_Scalere target-utilization são específicas do workload — copiar os números dos outros vai te machucar. - Contagem de sessões também pode mentir. Uma sessão presa em estado zumbi (partição de rede, sem disconnect limpo) infla o contador. Combine com heartbeat timeouts.
- Intervalos de report importam. Load balancers puxam métricas em intervalos regulares; sessões começam e terminam fluidamente. Você precisa de snapshots consistentes, não de consistência eventual na base do "vai dar certo".

O resumo da ópera
IA em tempo real move o balanceamento de carga de um problema de rede pra um problema de camada de aplicação. Três sinais importam:
- QPS → volume de chegada
- CPU/Memória → pressão atual
- Contagem de sessões ativas → concorrência comprometida
Nenhum deles sozinho é suficiente. As estratégias vencedoras sintetizam os três, e o backend — não o proxy — é o único componente com contexto suficiente pra reportar o estado das sessões com precisão. 🎯
O que estudar depois
Se você roda workloads stateful de longa duração, os mesmos instintos arquiteturais se aplicam em outros domínios. Dois deep dives que valem seu tempo:
- 📖 Como a Netflix Democratizou o ML: Construindo um Grafo Universal de Ciclo de Vida de Modelos — gerenciamento de metadados para pipelines de ML de longa duração.
- 📖 Privacy by Design: Como o Airbnb Construiu Features Sociais Context-Aware Sem Sacrificar a Confiança — arquitetura stateful com confiança do usuário como restrição de primeira classe.
Conforme agentes de IA vão pra produção, a infraestrutura precisa acompanhar. Pare de balancear requests. Comece a balancear conversas. 🚀