Nginx como load balancer

Quando uma única instância da aplicação não dá conta do tráfego ou você precisa de zero downtime nos deploys, o Nginx distribui requisições entre múltiplos backends. Com upstream configurado, você tem round-robin, failover automático e conexões ponderadas sem nenhum software adicional.

Configurar upstream com múltiplos backends

Bloco upstream define o pool de servidores que receberão as requisições:

nginx
# /etc/nginx/conf.d/load-balancer.conf

upstream api_cluster {
    # Round-robin (padrão) — distribui igualmente entre os servidores
    server 10.0.0.10:3000;
    server 10.0.0.11:3000;
    server 10.0.0.12:3000;

    # Keepalive: reutilizar conexões com backends
    keepalive 64;
}

server {
    listen 443 ssl http2;
    server_name api.seudominio.com.br;

    ssl_certificate     /etc/letsencrypt/live/api.seudominio.com.br/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/api.seudominio.com.br/privkey.pem;

    location / {
        proxy_pass http://api_cluster;
        proxy_http_version 1.1;
        proxy_set_header Connection "";
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

Algoritmos de balanceamento

Escolha o algoritmo adequado ao tipo de workload:

nginx
# 1. Round-Robin (padrão)
# Distribui sequencialmente: req1→srv1, req2→srv2, req3→srv3, req4→srv1...
upstream api_rr {
    server 10.0.0.10:3000;
    server 10.0.0.11:3000;
}

# 2. Least Connections — envia para o servidor com menos conexões ativas
# Melhor para requisições de duração variável (uploads, websockets)
upstream api_lc {
    least_conn;
    server 10.0.0.10:3000;
    server 10.0.0.11:3000;
}

# 3. IP Hash — mesmo cliente sempre vai para o mesmo servidor
# Útil para sessões sem store externo (não recomendado para REST stateless)
upstream api_ip {
    ip_hash;
    server 10.0.0.10:3000;
    server 10.0.0.11:3000;
}

# 4. Weighted — servidor mais potente recebe mais requisições
upstream api_weighted {
    server 10.0.0.10:3000 weight=3;   # recebe 3x mais tráfego
    server 10.0.0.11:3000 weight=1;
}

# 5. Random (disponível no Nginx Plus e versões recentes mainline)
upstream api_random {
    random two least_conn;
    server 10.0.0.10:3000;
    server 10.0.0.11:3000;
    server 10.0.0.12:3000;
}

Failover automático e parâmetros de saúde

Configure o Nginx para remover automaticamente servidores com falha:

nginx
upstream api_cluster {
    server 10.0.0.10:3000 max_fails=3 fail_timeout=30s;
    server 10.0.0.11:3000 max_fails=3 fail_timeout=30s;

    # Servidor de backup (só usado quando os outros estão indisponíveis)
    server 10.0.0.12:3000 backup;

    keepalive 64;
}

# Parâmetros:
# max_fails=3       : após 3 falhas consecutivas, marca o servidor como down
# fail_timeout=30s  : período de observação das falhas E tempo que fica down
# backup            : não recebe tráfego normal, apenas quando outros falham
# down              : marcar permanentemente como indisponível
# weight=N          : peso relativo no balanceamento

# Exemplo com servidor em manutenção:
upstream api_cluster {
    server 10.0.0.10:3000;
    server 10.0.0.11:3000 down;     # em manutenção — não recebe tráfego
    server 10.0.0.12:3000;
}

Deploy sem downtime com upstream dinâmico

Estratégia para deploy rolling sem interromper o serviço:

bash
# Deploy sem downtime: remover um servidor, atualizar, reintroduzir

# 1. Marcar srv2 como down no nginx.conf:
# server 10.0.0.11:3000 down;
sudo nginx -s reload    # tráfego vai apenas para srv1 e srv3

# 2. Aguardar conexões ativas no srv2 terminarem:
# (verificar no servidor): ss -tnp | grep :3000

# 3. Atualizar aplicação no srv2
ssh deploy@10.0.0.11 "cd /opt/api && git pull && npm ci && pm2 reload all"

# 4. Reativar srv2:
# server 10.0.0.11:3000;   (remover 'down')
sudo nginx -s reload

# Repetir para srv1 e srv3

# Alternativa automática com script:
for SERVER in 10.0.0.10 10.0.0.11 10.0.0.12; do
  echo "Atualizando $SERVER..."
  # Marcar como down no config e reload
  ssh deploy@$SERVER "cd /opt/api && git pull && npm ci && pm2 reload all"
  # Reativar e reload
  sleep 10   # aguardar estabilização
done

Load balancer para múltiplos serviços

Balancear diferentes serviços com upstreams separados:

nginx
# /etc/nginx/conf.d/multi-upstream.conf

# Pool para a API principal
upstream api {
    least_conn;
    server 10.0.0.10:3000 max_fails=3 fail_timeout=30s;
    server 10.0.0.11:3000 max_fails=3 fail_timeout=30s;
    keepalive 32;
}

# Pool para processamento pesado (workers)
upstream workers {
    server 10.0.0.20:4000 max_fails=2 fail_timeout=60s;
    server 10.0.0.21:4000 max_fails=2 fail_timeout=60s;
    keepalive 16;
}

# Pool para arquivos estáticos (ou CDN origin)
upstream static {
    server 10.0.0.30:5000;
    keepalive 8;
}

server {
    listen 443 ssl http2;
    server_name seudominio.com.br;

    location /api/     { proxy_pass http://api/;     }
    location /process/ { proxy_pass http://workers/; }
    location /assets/  { proxy_pass http://static/;  }
}

Não quer configurar manualmente?

Implante o VPS em menos de 5 minutos com a Runstack. Infraestrutura da OPEN Datacenter, com servidores em São Paulo.

Perguntas frequentes

Não, apenas health check passivo (detecta falhas durante requisições reais). Nginx Plus tem health check ativo (verifica periodicamente mesmo sem tráfego). Alternativas open-source: HAProxy tem health check ativo nativo; para Nginx, use o módulo third-party nginx_upstream_check_module ou um script externo que marca servidores como down via nginx -s reload.

Opção 1: Sticky sessions com ip_hash, mesmo IP sempre vai ao mesmo servidor. Limitação: desbalanceia quando IPs mudam (CGNAT, mobile). Opção 2: Sessões em store externo (Redis), todos os servidores leem/escrevem sessões no Redis. Recomendado para aplicações stateless. Opção 3: JWT, sem sessão server-side, tokens carregados pelo cliente.

Nginx: faz proxy + load balancer + serve estáticos, um único serviço para tudo. Mais simples de operar. HAProxy: focado exclusivamente em load balancing e proxy, mais features avançadas (ACLs, health checks ativos, estatísticas detalhadas), mais performático para grandes volumes. Para a maioria das VPS: Nginx é suficiente e mais simples.

Nginx open-source: módulo stub_status para métricas básicas. Habilite: location /nginx-status { stub_status; allow 127.0.0.1; deny all; }. Para métricas detalhadas por upstream: Nginx Plus (pago) ou use prometheus-nginxlog-exporter para parsear logs e expor no Prometheus. Grafana Dashboard 12559 visualiza essas métricas.

Não há número mágico, depende do tráfego e do tamanho de cada instância. Regra prática: 2 servidores para alta disponibilidade, 3+ para escala horizontal. Com 2 servidores: quando um cai, o outro absorve 100%, certifique-se que cada servidor aguenta a carga total. Com 3+: quando um cai, os demais absorvem 50% a mais cada.