Balanceamento básico no Nginx: upstream, round-robin e verificações simples

Capítulo 12

Tempo estimado de leitura: 8 minutos

+ Exercício

O que é balanceamento no Nginx (e o que ele não é)

Balanceamento de carga é a distribuição de requisições entre múltiplas instâncias de um mesmo serviço (backends), com o objetivo de melhorar capacidade e reduzir o impacto de picos. No Nginx, isso é feito principalmente com o bloco upstream, que define um “pool” de servidores, e um proxy_pass apontando para esse pool.

É importante separar dois conceitos:

  • Balanceamento: distribuir tráfego entre instâncias saudáveis para aumentar throughput e reduzir latência média.
  • Alta disponibilidade (HA): garantir que o ponto de entrada continue acessível mesmo se um componente cair. Ter dois backends atrás de um único Nginx melhora a resiliência do serviço, mas não elimina o Nginx como ponto único de falha. HA normalmente envolve redundância do próprio Nginx (ou de um load balancer externo), IP flutuante, health checks ativos, etc.

Bloco upstream e round-robin (padrão)

O algoritmo padrão do Nginx para upstream é round-robin: a cada nova requisição, ele alterna o backend escolhido, distribuindo de forma relativamente uniforme (considerando conexões e disponibilidade).

Exemplo mínimo de upstream

upstream app_pool {    server 127.0.0.1:3001;    server 127.0.0.1:3002;}

Quando você usa proxy_pass http://app_pool;, o Nginx passa a encaminhar requisições alternando entre :3001 e :3002.

Pesos (weight): mais tráfego para quem aguenta mais

Você pode ajustar a proporção de tráfego com weight. Um servidor com peso 2 tende a receber aproximadamente o dobro de requisições de um servidor com peso 1.

Continue em nosso aplicativo e ...
  • Ouça o áudio com a tela desligada
  • Ganhe Certificado após a conclusão
  • + de 5000 cursos para você explorar!
ou continue lendo abaixo...
Download App

Baixar o aplicativo

upstream app_pool {    server 127.0.0.1:3001 weight=2;    server 127.0.0.1:3002 weight=1;}

Isso é útil quando uma instância tem mais CPU/memória, ou quando você está fazendo uma migração gradual (canary simples) sem ferramentas externas.

Falhas e “quarentena” do upstream: max_fails e fail_timeout

Em configuração básica, o Nginx não faz health check ativo (ele não fica “pingando” o backend). Em vez disso, ele aprende por falhas durante o tráfego real. Duas diretivas comuns:

  • max_fails: número de falhas que, ao ocorrerem dentro de uma janela, fazem o Nginx considerar o servidor temporariamente indisponível.
  • fail_timeout: janela de tempo para contar falhas e também o período típico em que o servidor fica “marcado como ruim” antes de ser tentado novamente.

Exemplo:

upstream app_pool {    server 127.0.0.1:3001 max_fails=2 fail_timeout=10s;    server 127.0.0.1:3002 max_fails=2 fail_timeout=10s;}

Interpretação prática: se um backend falhar 2 vezes em até 10 segundos, ele tende a ser evitado por cerca de 10 segundos, e depois volta a ser testado conforme novas requisições chegarem.

O que conta como “falha”?

Em geral, falhas de conexão com o upstream (connection refused, timeout, reset) contam. Já códigos HTTP 500/502/503 podem ou não influenciar dependendo de como você configura proxy_next_upstream (mais abaixo). Sem ajustes, o Nginx pode retornar o erro ao cliente sem tentar outro upstream em algumas situações.

Limitações de checagens na configuração básica

Sem módulos/complementos de health check ativo, o Nginx “descobre” problemas apenas quando há tráfego. Isso traz limitações:

  • Se o tráfego for baixo, um backend ruim pode demorar a ser detectado.
  • Um backend pode “voltar” e ainda assim falhar intermitentemente; o Nginx vai alternar tentativas conforme o tráfego.
  • Você não tem, nativamente, uma URL de health check ativa por backend (ex.: /health) sendo consultada periodicamente pelo Nginx na configuração básica.

Mesmo assim, max_fails e fail_timeout já ajudam a reduzir o impacto de quedas óbvias (porta fechada, processo morto, etc.).

Laboratório: duas instâncias e um Nginx distribuindo tráfego

Objetivo do laboratório: subir duas instâncias simples em portas diferentes, colocar o Nginx na frente com upstream e confirmar a distribuição e o comportamento quando uma instância falha.

1) Suba duas instâncias de aplicação (exemplo com Python)

Em dois terminais diferentes, rode servidores HTTP simples servindo uma resposta diferente. Uma forma prática é criar duas pastas com um index.html distinto.

No Terminal A:

mkdir -p /tmp/app1 && echo 'APP1' > /tmp/app1/index.htmlcd /tmp/app1python3 -m http.server 3001

No Terminal B:

mkdir -p /tmp/app2 && echo 'APP2' > /tmp/app2/index.htmlcd /tmp/app2python3 -m http.server 3002

Teste direto (sem Nginx) para confirmar:

curl -s http://127.0.0.1:3001/; echocurl -s http://127.0.0.1:3002/; echo

2) Configure o upstream e o server que faz proxy para o pool

Crie um arquivo de configuração do site (ajuste o caminho conforme sua organização). O foco aqui é o bloco upstream e o uso de logs para observabilidade.

upstream app_pool {    server 127.0.0.1:3001 weight=1 max_fails=2 fail_timeout=10s;    server 127.0.0.1:3002 weight=1 max_fails=2 fail_timeout=10s;}log_format upstream_debug '$remote_addr - $time_local '                          '"$request" $status '                          'upstream=$upstream_addr '                          'upstream_status=$upstream_status '                          'rt=$request_time urt=$upstream_response_time';server {    listen 8080;    access_log /var/log/nginx/upstream_access.log upstream_debug;    error_log  /var/log/nginx/upstream_error.log warn;    location / {        proxy_pass http://app_pool;        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;        proxy_next_upstream error timeout invalid_header http_502 http_503 http_504;        proxy_next_upstream_tries 2;    }}

Pontos importantes:

  • log_format upstream_debug inclui $upstream_addr e $upstream_status, essenciais para enxergar para qual backend cada requisição foi enviada.
  • proxy_next_upstream ... permite que, em certos erros, o Nginx tente outro backend em vez de falhar imediatamente para o cliente.
  • proxy_next_upstream_tries 2 limita quantas tentativas totais serão feitas (útil para evitar “loop” de tentativas em cascata).

3) Recarregue o Nginx e gere tráfego

Recarregue a configuração (use o comando adequado ao seu ambiente). Em seguida, faça várias requisições:

for i in $(seq 1 10); do  curl -s http://127.0.0.1:8080/; echo;done

Você deve ver alternância entre APP1 e APP2 (round-robin).

4) Confirme a distribuição via logs (observabilidade)

Agora observe o log de acesso customizado:

tail -f /var/log/nginx/upstream_access.log

Procure por linhas como:

"GET / HTTP/1.1" 200 upstream=127.0.0.1:3001 upstream_status=200 ..."GET / HTTP/1.1" 200 upstream=127.0.0.1:3002 upstream_status=200 ...

Isso confirma, de forma objetiva, qual upstream atendeu cada requisição.

Simulando falha de um upstream e observando o comportamento

1) Derrube uma instância

Pare o servidor do Terminal B (porta 3002) com Ctrl+C.

2) Gere tráfego novamente

for i in $(seq 1 10); do  curl -i http://127.0.0.1:8080/ | head -n 1;done

Com proxy_next_upstream habilitado, a tendência é que o Nginx tente o backend que falhou e, ao detectar erro de conexão/timeout, faça failover para o outro (até o limite de tentativas). Você deve ver respostas 200 continuarem vindo, desde que pelo menos um upstream esteja saudável.

3) Verifique nos logs o failover e a marcação de falha

No upstream_access.log, observe upstream=... e upstream_status=.... Em falhas, você pode ver algo como:

upstream=127.0.0.1:3002 upstream_status=502, 200

Isso indica que a primeira tentativa foi no :3002 e falhou (502 gerado pelo proxy), e a segunda tentativa foi no :3001 e teve sucesso (200). O formato pode variar conforme o tipo de falha e o que foi registrado.

No upstream_error.log, você pode ver mensagens do tipo connect() failed (111: Connection refused) while connecting to upstream, úteis para confirmar a causa.

Ajustes úteis para testes: weight e comportamento em degradação

Testando weight na prática

Altere o upstream para dar mais tráfego ao APP1:

upstream app_pool {    server 127.0.0.1:3001 weight=3 max_fails=2 fail_timeout=10s;    server 127.0.0.1:3002 weight=1 max_fails=2 fail_timeout=10s;}

Recarregue o Nginx, suba novamente o APP2 e repita o loop de curl. No log, conte ocorrências de upstream=127.0.0.1:3001 versus :3002; a proporção tende a se aproximar de 3:1.

Entendendo o “retorno” de um upstream após falha

Depois que um upstream é marcado como indisponível por fail_timeout, ele volta a ser elegível e será testado novamente conforme novas requisições chegarem. Se ele ainda estiver fora, novas falhas vão mantê-lo sendo evitado. Esse ciclo é um motivo para você observar logs durante incidentes: o comportamento é guiado por falhas reais, não por checagens proativas.

Checklist do laboratório (o que você deve conseguir observar)

  • Round-robin alternando respostas APP1/APP2 quando ambos estão no ar.
  • $upstream_addr no log confirmando para qual backend cada requisição foi.
  • Ao derrubar um backend, o Nginx registrando erros no error_log e mantendo respostas 200 via o backend saudável (quando proxy_next_upstream permite).
  • Após alguns erros, o backend com falha sendo evitado temporariamente (efeito de max_fails/fail_timeout), reduzindo tentativas repetidas nele.

Agora responda o exercício sobre o conteúdo:

Em uma configuração básica de balanceamento com upstream, qual cenário descreve corretamente como o Nginx lida com backends que falham?

Você acertou! Parabéns, agora siga para a próxima página

Você errou! Tente novamente.

Na configuração básica, o Nginx não faz checagem ativa; ele aprende por falhas reais. Com max_fails/fail_timeout, um backend pode ser evitado por um período, e com proxy_next_upstream o Nginx pode tentar outro backend após certos erros.

Próximo capitúlo

Padrões de configuração para pequenos projetos com Nginx: templates e manutenção

Arrow Right Icon
Capa do Ebook gratuito Nginx para Iniciantes: Servidor Web, Reverse Proxy e Balanceamento Básico
92%

Nginx para Iniciantes: Servidor Web, Reverse Proxy e Balanceamento Básico

Novo curso

13 páginas

Baixe o app para ganhar Certificação grátis e ouvir os cursos em background, mesmo com a tela desligada.