Load balancer: como distribuir tráfego com segurança
Como um load balancer distribui requests entre backends para escala e alta disponibilidade: camada 4 vs 7, algoritmos, health checks e sessões stateless.
Você subiu mais uma instância da sua aplicação porque uma sozinha não aguenta mais o tráfego, e agora tem duas máquinas iguais rodando o mesmo código. O problema é óbvio: como o usuário sabe para qual delas mandar a requisição? Apontar o DNS direto para um IP funciona até a máquina cair às três da manhã. E quando você precisa de uma terceira instância, recomeça tudo. O load balancer existe para resolver exatamente essa bagunça: ele fica na frente dos seus backends e decide, requisição por requisição, quem atende.
Este texto cobre o que um load balancer resolve na prática, a diferença entre operar na camada 4 e na camada 7, os algoritmos de distribuição, e por que health checks e sessões stateless são a parte que realmente importa.
O que um load balancer resolve
Um load balancer recebe todo o tráfego que chega no seu domínio e o distribui entre um conjunto de backends — o que costumamos chamar de pool ou upstream. Dois ganhos vêm de graça com isso. O primeiro é escala horizontal: em vez de comprar uma máquina maior (caro e com teto), você adiciona instâncias iguais e o LB passa a mandar tráfego para elas. O segundo é alta disponibilidade: se um backend morre, o LB para de mandar requisições para ele e o usuário nem percebe.
Sem load balancer, esses dois objetivos viram trabalho manual e frágil. Com ele, escalar é adicionar um endereço ao pool, e disponibilidade é uma configuração de health check. A diferença entre uma arquitetura que aguenta um pico de tráfego e uma que cai no primeiro feriado costuma ser essa caixa no meio.
Camada 4 versus camada 7
A distinção mais importante de configuração é em qual camada do modelo de rede o LB opera.
Um load balancer de camada 4 trabalha no nível de TCP/UDP. Ele vê endereços IP e portas, e encaminha pacotes sem abrir o conteúdo. É rápido e barato em CPU porque não interpreta nada do que está passando — não sabe se ali dentro tem HTTP, gRPC ou um protocolo binário qualquer. Use camada 4 quando você precisa de throughput bruto e não precisa de decisões baseadas no conteúdo da requisição.
Um load balancer de camada 7 trabalha no nível de HTTP. Ele lê o request inteiro: método, path, headers, cookies. Isso permite roteamento inteligente — mandar /api/* para um pool e /static/* para outro, ou rotear por header de versão, ou aplicar regras por hostname. O custo é que ele precisa fazer o parsing de HTTP e, normalmente, terminar o TLS para enxergar o conteúdo. Na prática, a maioria das aplicações web quer camada 7.
Layer 7 LB
/api/* ──────────────────────► pool-api (3 instâncias)
/static/* ──────────────────────► pool-static (2 instâncias)
/ ──────────────────────► pool-web (4 instâncias)
Algoritmos de distribuição
Decidir para qual backend mandar a próxima requisição é o trabalho do algoritmo de balanceamento. Os três que você vai encontrar em quase todo lugar:
Round-robin distribui em sequência: primeira requisição para o backend A, segunda para o B, terceira para o C, e volta. É simples e funciona bem quando todas as instâncias têm capacidade parecida e as requisições custam mais ou menos o mesmo. É o padrão da maioria dos LBs por bom motivo.
Least-connections manda a próxima requisição para o backend que está com menos conexões ativas no momento. É melhor que round-robin quando as requisições têm durações muito diferentes — uma que demora 50ms e outra que demora 8 segundos. Com round-robin puro, um backend pode acumular várias requisições lentas enquanto outro está ocioso; least-connections corrige isso naturalmente.
Hashing por IP calcula um hash do IP de origem e sempre manda aquele cliente para o mesmo backend. Serve para criar afinidade sem cookies, mas tem o mesmo problema das sticky sessions, que vou atacar mais à frente.
Health checks: o coração da disponibilidade
Distribuir tráfego é a parte fácil. A parte que define se a sua alta disponibilidade é real ou teatro é o health check. O LB testa cada backend de tempos em tempos e, quando um falha, tira aquela instância do pool. As requisições seguintes vão para os backends saudáveis, sem erro chegando no usuário.
Aqui está o detalhe que separa um health check bom de um inútil: o que conta como "saudável". Um health check de TCP só verifica se a porta aceita conexão — mas um processo pode aceitar conexão e ainda assim estar com o banco de dados fora do ar, devolvendo erro em tudo. Por isso, prefira um health check de camada 7 que bate em um endpoint real, tipo /health, e julga pelo status HTTP da resposta. O health check de um load balancer decide pelo status HTTP do backend: um 200 mantém a instância no pool, um 503 a remove. Faça o seu endpoint /health checar as dependências de verdade (banco, cache, fila) e responder o código certo — um 200 mentiroso é pior do que não ter health check, porque esconde o problema.
health check:
path: /health
interval: 5s
timeout: 2s
healthy_threshold: 2 # 2 respostas 200 seguidas → volta ao pool
unhealthy_threshold: 3 # 3 falhas seguidas → sai do pool
Os thresholds existem para evitar que um soluço momentâneo derrube uma instância boa. Você quer remover rápido um backend que de fato morreu, mas não quer expulsar um que só teve um GC pause de meio segundo.
Sticky sessions e por que evitá-las
Sticky session (ou session affinity) é quando o LB amarra um usuário a um backend específico — normalmente via cookie — e manda todas as requisições daquele usuário para a mesma instância. A motivação clássica é que a aplicação guarda a sessão do usuário na memória local daquele processo. Se a próxima requisição cair em outra instância, a sessão "some" e o usuário é deslogado.
Funciona, mas é um remendo. Veja o que sticky session quebra: quando o backend ao qual o usuário está colado cai, a sessão dele vai junto, e o health check, que era para proteger o usuário, agora também o desloga. O balanceamento fica torto, porque um nó com muitos usuários colados acumula carga enquanto outro fica ocioso. E deploy fica doloroso, porque derrubar uma instância significa derrubar as sessões grudadas nela.
A opinião aqui é firme: torne suas instâncias stateless. Não guarde sessão na memória local do processo. Coloque-a em um store compartilhado — Redis, um banco, qualquer coisa que todas as instâncias enxerguem igualmente. Com sessão em store compartilhado, qualquer backend atende qualquer requisição de qualquer usuário, e o LB fica livre para mandar tráfego para onde fizer mais sentido. Sticky session não é uma feature que você liga para ganhar performance; é um sintoma de que o estado está no lugar errado. Resolva a causa, não o sintoma.
TLS termination e failover
Duas peças que completam o quadro. TLS termination é o LB encerrar a conexão HTTPS, descriptografar o tráfego e falar HTTP simples com os backends na rede interna. Isso centraliza os certificados em um lugar só (em vez de espalhar por todas as instâncias) e libera CPU dos backends, que não precisam mais fazer o handshake de TLS. Se a rede entre o LB e os backends não for confiável, você pode reencriptar no trajeto interno — mas para a maioria dos casos dentro de uma VPC, terminar no LB é o padrão.
Failover é o comportamento do LB quando backends ficam indisponíveis: ele redireciona o tráfego para os que sobraram. Em setups mais sérios, isso se estende para failover entre regiões ou zonas de disponibilidade inteiras. Vale lembrar que load balancer e CDN resolvem problemas diferentes mas complementares — se você ainda não tem clareza sobre essa fronteira, vale entender o que é uma CDN antes de desenhar a borda da sua infraestrutura.
Perguntas frequentes
Load balancer e reverse proxy são a mesma coisa?
São conceitos que se sobrepõem mas não são idênticos. Um reverse proxy fica na frente de servidores e encaminha requisições; um load balancer é um reverse proxy especializado em distribuir carga entre vários backends. Na prática, ferramentas como Nginx e HAProxy fazem os dois papéis, então a linha é borrada. A diferença está na intenção: você usa "load balancer" quando o foco é distribuir e dar disponibilidade.
Onde colocar o SSL: no load balancer ou em cada backend?
Na grande maioria dos casos, no load balancer, via TLS termination. Você centraliza a gestão de certificados, simplifica a renovação e tira o custo de CPU do handshake de cima dos backends. Só faz sentido terminar o TLS em cada backend se a regulação ou a topologia exigir criptografia ponta a ponta — e mesmo aí, normalmente se reencripta entre o LB e o backend em vez de abrir mão do LB.
Quantos backends eu preciso para ter alta disponibilidade?
No mínimo dois, e em zonas ou hosts diferentes. Com uma única instância, o load balancer não tem para onde mandar tráfego quando ela cai — ele só repassa o erro. Dois é o piso para que a queda de um backend seja absorvida; três ou mais dão margem para você também tirar uma instância para deploy sem ficar sem redundância.
Sticky session é sempre ruim?
Não em termos absolutos, mas quase sempre é um sinal de problema de arquitetura. Se você precisa de sticky session porque guarda sessão na memória local, a solução certa é mover a sessão para um store compartilhado, não amarrar o usuário a um nó. Há casos legítimos e raros — protocolos com estado de conexão longo, por exemplo — mas, para aplicação web comum, trate sticky session como dívida técnica.
O que levar daqui
Um load balancer não é só uma caixa que reparte requisições; é a peça que transforma "tenho um servidor" em "tenho um sistema que escala e não cai". Comece escolhendo a camada certa — camada 7 para a maioria das aplicações web — e um algoritmo simples como round-robin ou least-connections. Invista de verdade no health check, porque é ele que faz a disponibilidade ser real: aponte para um endpoint que checa dependências e julga pelo status HTTP. E acima de tudo, torne suas instâncias stateless. Quando qualquer backend pode atender qualquer requisição, o load balancer faz o trabalho dele direito, o deploy deixa de doer e você nunca mais precisa de sticky session para esconder estado mal posicionado.
- 01 Nubank Croma: o que vem no plano, quanto custa e pra quem realmente compensa O Nubank lançou o Croma, um plano de média renda entre o cartão gratuito e o Ultravioleta. Veja o que está incluído, o cashback real, os R$ 39 de mensalidade (e como zerar) e faça a conta antes de aderir.
- 02 Testes unitários: o que testar e o que evitar O que separa testes que protegem comportamento real dos que só inflam coverage e viram fardo na hora de refatorar.