02 - Hardware vs Software (HAProxy, Nginx)
video: https://youtu.be/... no frontmatter da nota.Hardware vs Software (HAProxy, Nginx)
Balanceamento de carga pode ser entregue por appliances dedicados de hardware ou por software rodando em servidores comuns e máquinas virtuais, e essa divisão define custo, flexibilidade e modelo de operação. O appliance de hardware é uma caixa pronta, com ASICs de criptografia, suporte contratual do fabricante e desempenho previsível, mas com preço alto, ciclo de aquisição lento e capacidade fixada no dia da compra. O software, representado por HAProxy e Nginx, roda em qualquer infraestrutura, escala com provisionamento e evolui em ciclos de semanas, sendo o modelo dominante em nuvem e o padrão de facto em arquiteturas modernas. A discussão não é religiosa, é de requisito: datacenters próprios com requisitos de certificação e desempenho garantido ainda justificam hardware, enquanto praticamente todo ambiente de nuvem resolve o problema com software, gerenciado ou não. O domínio do tema, para quem projeta produção, está em entender o que cada ferramenta de software sabe fazer bem, porque é com elas que a maioria dos ambientes realmente opera.
Conceito e problema que resolvem
O appliance de hardware nasceu num mundo em que servidores eram caros, a rede era o gargalo e a compra de capacidade era projeto de meses. Fornecedores como F5, Citrix e A10 entregam caixas com aceleração dedicada de TLS, compressão em silício e um ecossistema de configuração proprietário, com SLA de suporte e substituição física. O ganho é previsibilidade de desempenho e responsabilidade contratual; o custo é a licença, a rigidez e a obsolescência programada, porque redimensionar significa comprar nova caixa.
O software resolve o mesmo problema com produtos que competem em desempenho com hardware dedicado: HAProxy sustenta centenas de milhares de conexões simultâneas em um nó dimensionado, e Nginx, nascido para resolver o problema C10K, serve de proxy reverso e balanceador com consumo de memória mínimo por conexão. O ganho é elasticidade, custo marginal próximo de zero e automação total, já que configuração é arquivo texto versionado em repositório. O custo é assumir a operação: patches, dimensionamento, alta disponibilidade do próprio balanceador e expertise da equipe.
O problema que ambos resolvem é idêntico: distribuir carga entre destinos, remover destinos doentes do pool e servir de ponto único de entrada com terminação de protocolo. O que muda é o contrato de aquisição e a velocidade de mudança, e é nesse eixo que a decisão arquitetural se apoia.
HAProxy em detalhe
O HAProxy é um balanceador puro, focado em disponibilidade e desempenho, e é a referência quando a exigência é distribuição de alta precisão. Ele opera em dois modos principais: modo TCP, que encaminha fluxo bruto sem interpretar aplicação, e modo HTTP, que termina e inspeciona requisições, permitindo regras por path, header e cookie, equivalente funcional à distinção L4 e L7.
Os health checks do HAProxy são extensos: TCP, HTTP com verificação de código, envio de corpo e verificação de string, e checks específicos para PostgreSQL, MySQL, Redis, SMTP e LDAP, algo que poucos concorrentes oferecem. A retirada de destino respeita períodos de observação e drenagem, e os algoritmos cobrem round robin, least connections, source hash, URI hash e first, além de pesos dinâmicos.
A ferramenta de estatísticas é um diferencial operacional: a página de stats nativa e o socket de administração expõem em tempo real a taxa de requisição, a fila por backend, o estado de cada servidor e o tempo de resposta médio, e a mesma interface permite drenar um servidor em produção com um comando, sem reload. O runtime API via socket também permite adicionar e remover destinos sem reiniciar, o que integra bem com descoberta de serviço.
# Exemplo de configuração do HAProxy (haproxy.cfg)
global
maxconn 50000 # limite global de conexões simultâneas
log stdout format raw local0 # log estruturado para stdout, bom para contêiner
defaults
mode http # modo HTTP habilita inspeção de camada 7
log global
option httplog
timeout connect 5s # tempo para abrir conexão com o backend
timeout client 30s
timeout server 30s
retries 3
frontend entrada_api
bind *:443 ssl crt /etc/haproxy/certs/api.pem alpn h2,http/1.1
# Terminação TLS centralizada com negociação HTTP/2
# Roteamento por path: pedidos e relatorios em clusters distintos
acl path_pedidos path_beg /v1/pedidos
acl path_relatorios path_beg /v1/relatorios
use_backend bk_pedidos if path_pedidos
use_backend bk_relatorios if path_relatorios
default_backend bk_pedidos
backend bk_pedidos
balance leastconn # bom para tempos de resposta variáveis
option httpchk GET /healthz # health check HTTP real
http-check expect status 200
server pedidos-1 10.0.1.11:8080 check maxconn 500 weight 100
server pedidos-2 10.0.1.12:8080 check maxconn 500 weight 100
server pedidos-3 10.0.1.13:8080 check maxconn 500 weight 50 backup
listen estatisticas
bind *:8404
stats enable
stats uri /stats # painel de estatísticas nativo
Nginx em detalhe
O Nginx é mais amplo que um balanceador: é servidor web, proxy reverso, cache HTTP e balanceador, e essa amplitude é a razão de sua ubiquidade. Como proxy reverso, ele posiciona a aplicação atrás de um ponto que adiciona compressão, terminação TLS, cache de respostas estáticas e limitação de taxa, e o balanceamento é um recurso dentro desse contexto maior.
O bloco upstream define o pool de destinos e o algoritmo: round robin é o default, least_conn escolhe por menor número de conexões ativas, ip_hash fornece afinidade por IP de origem, e os pesos atribuem capacidade relativa. Os health checks ativos com sondagem de aplicação são recurso da edição comercial, enquanto a edição open source usa verificação passiva, marcando servidor como indisponível a partir de erros e timeouts observados no tráfego real, com max_fails e fail_timeout.
O ponto forte do Nginx em produção é atuar como camada única de edge: ele responde estático com eficiência extrema, cacheia respostas de APIs em proxy_cache com regras por header e TTL, aplica rate limiting por chave e concentra políticas de header de segurança. Em ambientes Kubernetes, essa mesma lógica aparece no ingress-nginx, o que multiplica o número de equipes que operam o produto sem perceber.
| Aspecto | Hardware (appliance) | HAProxy | Nginx |
|---|---|---|---|
| Modelo de aquisição | CAPEX, licença e suporte | Open source ou enterprise | Open source ou comercial |
| Desempenho por nó | Alto, aceleração dedicada | Altíssimo, otimizado para proxy | Alto, eficiente em estático |
| Modos de operação | TCP e HTTP completos | TCP e HTTP | HTTP e TCP (stream) |
| Health checks ativos | Sim, variados | Sim, com checks por banco | Passivo no open source |
| Cache de conteúdo | Sim | Não foco | Sim, proxy_cache |
| Elasticidade de escala | Compra de nova caixa | Provisionar mais nós | Provisionar mais nós |
| Curva de mudança | Semanas a meses | Minutos, reload sem queda | Minutos, reload sem queda |
| Caso ideal | Datacenter com SLA rígido | Balanceamento puro crítico | Edge, proxy e estático |
Algoritmos de distribuição
Os algoritmos são o vocabulário comum das duas ferramentas, e a escolha correta depende do padrão de latência da aplicação.
- Round robin: distribui ciclicamente sem olhar carga; correto quando os destinos são homogêneos e as requisições têm custo parecido.
- Weighted round robin: adiciona pesos, útil em migração gradual, mistura de hardware e canary com percentual controlado.
- Least connections: envia a requisição ao destino com menos conexões ativas; é a escolha padrão quando o tempo de resposta varia entre requisições, porque evita empilhar trabalho no nó mais lento.
- Source IP hash: derivado do IP do cliente, dá afinidade sem estado; serve como mitigação de sessão e ajuda em cache por origem.
- URI hash: deriva do URI da requisição, direcionando o mesmo recurso sempre ao mesmo destino, o que multiplica a eficiência de cache local por nó.
- First: sempre usa o destino menos carregado e só recorre ao seguinte ao atingir maxconn, maximizando economia em ambientes com escala vertical.
O erro frequente é tratar round robin como default universal: com requisições de custo desigual, ele gera filas desiguais perceptíveis no p99, e a troca por least connections costuma resolver sem mudar infraestrutura.
Alta disponibilidade e modelo de custo
O balanceador é o componente que não pode cair, e a solução para o ponto único de falha é par de nós com IP flutuante, tradicionalmente via VRRP com Keepalived no ambiente on-premises, e instâncias em zonas distintas com automação de failover na nuvem. O HAProxy se integra nativamente ao Keepalived, e o padrão é ativo-passivo com verificação de saúde entre pares; Nginx segue a mesma linha.
O TCO do hardware inclui aquisição, espaço, energia, renovação e contrato de suporte, com a peculiaridade de que capacidade ociosa é capital parado: dimensionar para o pico do ano seguinte significa pagar hoje. O modelo de software paga o que usa, e o custo cresce quase linear com o tráfego, o que é economicamente superior em carga variável e inferior quando a carga é constante e muito alta e o appliance amortizado já existe. A migração típica de custo acontece quando a caixa precisa ser renovada: substituir hardware por par de HAProxy em nuvem costuma reduzir o gasto mensal em ordem de grandeza, com ganho de automação.
Exemplo de Nginx como proxy reverso e balanceador
# Nginx concentrando proxy reverso, cache e balanceamento
upstream aplicacao {
least_conn; # menor número de conexões ativas
server app-1.internal:8080 weight=3; # nó maior recebe peso maior
server app-2.internal:8080 weight=1;
keepalive 32; # pool de conexões reutilizadas
}
# Zona compartilhada de estado passivo entre workers
proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=respostas:50m
max_size=2g inactive=10m use_temp_path=off;
server {
listen 443 ssl http2;
server_name app.exemplo.com.br;
# Limitação de taxa por IP: 20 requisições por segundo com rajada de 40
limit_req_zone $binary_remote_addr zone=api:10m rate=20r/s;
location /api/ {
limit_req zone=api burst=40 nodelay;
proxy_pass http://aplicacao;
proxy_http_version 1.1;
proxy_set_header Connection "";
# Cache de respostas GET por 5 minutos no edge
proxy_cache respostas;
proxy_cache_valid 200 5m;
proxy_cache_key "$scheme$request_method$host$request_uri";
add_header X-Cache-Status $upstream_cache_status;
}
location /healthz {
return 200 "ok\n"; # endpoint barato para sondas externas
}
}
# Bloco TCP puro (stream): balanceia Redis sem interpretar protocolo
stream {
upstream redis_pool {
server redis-1.internal:6379;
server redis-2.internal:6379;
}
server {
listen 6379;
proxy_pass redis_pool;
proxy_connect_timeout 3s;
}
}
Esse exemplo concentra os papéis que fazem o Nginx ser onipresente: terminação com HTTP/2, limitação de taxa, cache no edge, distribuição ponderada e balanceamento TCP puro de um serviço de estado. O mesmo arquivo serve de base para o ingress-nginx em Kubernetes, o que torna o domínio da sintaxe transferível entre ambientes. A leitura arquitetural é que o Nginx é ferramenta de camada de borda, e o HAProxy é ferramenta de distribuição especializada; os dois no mesmo desenho são comuns e não redundantes, cada um cuidando do seu papel.
Erros comuns e boas práticas
- Balanceador como ponto único: um só nó de HAProxy ou Nginx é o elo mais frágil do desenho; sempre par com failover, em zonas distintas.
- Reload sem verificar sintaxe: mudança de configuração com erro derruba o serviço no reload; valide sempre com o modo de teste do binário antes de aplicar.
- Sem logs de decisão: sem registro de destino escolhido e tempo de resposta, investigar desequilíbrio é chutar; habilite logs completos por requisição.
- Health check passivo onde deveria ser ativo: esperar erro real para retirar destino atrasa a reação; em HAProxy, configure sondas ativas por aplicação.
- Misturar papéis sem plano de capacidade: Nginx que serve estático, cacheia e balanceia precisa de dimensionamento dedicado, senão o cache compete com o proxy por CPU e disco.
- Ignorar limites do sistema operacional: file descriptors, portas efêmeras e buffers de rede limitam o software antes do hardware; ajuste sysctl no dimensionamento.
A boa prática consolidada é versionar a configuração em repositório, validar em pipeline, aplicar com reload sem queda e monitorar o próprio balanceador como primeiro sinal de incidente. Em nuvem gerenciada, o mesmo pensamento se aplica ao avaliar o serviço gerenciado contra o par auto-hospedado: o gerenciado elimina operação e cobra por uso, e o auto-hospedado dá controle total e exige time dedicado, exatamente o mesmo eixo de trade-off do hardware contra o software.