Black November

ATÉ 50% OFF

TÁ ACABANDO!

0 dias

0 horas

0 min

0 seg

1
resposta

[Dúvida] Problemas com o Load Balancer

Estou apresentando problemas com meu Load Balancer. Quando atualizo a página do navegador (até mesmo usando o curl), a única mensagem que aparece é a do Servico 1, e nada do Servico 2. Quando acesso individualmente a porta 8001 e 8002, funciona. Elas exibem mensagens diferentes (index.html diferentes). Agora quando acesso o 8003, o Load Balancer não faz com que os servidores troquem.

nginx.conf:

user nginx;
worker_processes auto;

error_log /var/log/nginx/error.log notice;
pid /run/nginx.pid;

events {
worker_connections 1024;
}

http {
include /etc/nginx/mime.types;
default_type application/octet-stream;

log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                  '$status $body_bytes_sent "$http_referer" '
                  '"$http_user_agent" "$http_x_forwarded_for"';

access_log  /var/log/nginx/access.log  main;

sendfile        on;
#tcp_nopush     on;

keepalive_timeout  65;

#gzip  on;

include /etc/nginx/conf.d/*.conf;
include /etc/nginx/services/*.conf;

}

##############

load.conf:

upstream services {
server localhost:8001;
server localhost:8002;
}

server {
listen 8003;
server_name localhost;

location / {
    proxy_http_version 1.1;
    proxy_set_header Connection "";
    proxy_pass http://services;
}

}

microsservices.conf:

server {
listen 8001;

server_name  localhost;

location / {
    root   /nginx/servers/server1;
    index  index.html index.htm;
}

}

server {
listen 8002;

server_name  localhost;

location / {
    root   /nginx/servers/server2;
    index  index.html index.htm;
}

}

default.conf:

server {
listen 8080;
listen [::]:80;
server_name localhost;

location / {
    proxy_pass http://localhost:8003;
}

location /servico1 {
proxy_pass http://localhost:8001/;
}

location /servico2 {
proxy_pass http://localhost:8002/;
}	   

}

Matricule-se agora e aproveite até 50% OFF

O maior desconto do ano para você evoluir com a maior escola de tecnologia

QUERO APROVEITAR
1 resposta

Oii, Franscico.

Vamos por partes. O seu “sintoma”, o balanceador sempre cair no serviço 1 quando você atualiza a página, é típico de conexões persistentes (keep-alive) “prendendo” a mesma conexão ao mesmo upstream. Com o HTTP/1.1 entre o NGINX (na porta 8003) e os upstreams, o NGINX tende a reutilizar a mesma conexão para requisições subsequentes; na prática isso parece “grudar” no primeiro servidor que atendeu.

A sua load.conf contém:

location / {
    proxy_http_version 1.1;
    proxy_set_header Connection "";
    proxy_pass http://services;
}

Essas duas linhas favorecem a reutilização da conexão upstream. Resultado: em um cenário de navegação normal (browser abrindo e recarregando a mesma aba), você não enxerga o round-robin.

Como confirmar rapidamente:

Teste em linha de comando forçando fechamento de conexão a cada requisição:

# força HTTP/1.0 (sem keep-alive por padrão)
for i in {1..10}; do curl --http1.0 -s http://localhost:8003/ | head -n1; done

# ou força fechar a conexão
for i in {1..10}; do curl -H "Connection: close" -s http://localhost:8003/ | head -n1; done

Se alternar entre os conteúdos de server1 e server2, o round-robin está funcionando; o que “prende” é a conexão persistente.

Três soluções (escolha 1)

  1. Solução mais simples (didática): desligar keep-alive para upstream

    Troque o bloco location / do seu balanceador para:

    location / {
        proxy_http_version 1.0;          # volta ao 1.0
        proxy_set_header Connection close;# garante fechamento
        proxy_pass http://services;
    }
    

    Reinicie/recarregue:

    nginx -t && nginx -s reload
    

    Com isso, cada reload de página abrirá uma nova conexão upstream e você verá a alternância entre 8001 e 8002.

  2. Manter HTTP/1.1, mas ainda assim evitar “grudar”

    Remova as linhas que você adicionou:

    # proxy_http_version 1.1;
    # proxy_set_header Connection "";
    proxy_pass http://services;
    

    O NGINX voltará ao comportamento padrão (HTTP/1.0 para upstream), fechando a conexão a cada requisição.

  3. Se quiser HTTP/1.1 por algum motivo (WebSocket, SSE, etc.)

    Ainda dá para tornar a experiência “menos pegajosa”, mas é mais avançado. Exemplos:

    • Fechar a conexão do cliente após cada resposta:

      keepalive_requests 1;
      

      (no bloco http { ... }).
      Isso força o navegador a abrir nova conexão a cada reload, o que indiretamente resulta em nova seleção de upstream.

    • Ou manter 1.1 apenas onde realmente precisa (ex.: uma location /ws para WebSocket), deixando o resto com 1.0.

Checklist de conferência:

  • Valide a config: nginx -t deve sair “ok”.

  • Recarregue: nginx -s reload.

  • Veja logs por upstream (opcional, mas útil):

    # em microsservices.conf
    server {
        listen 8001;
        access_log /var/log/nginx/servico1.log main;
        ...
    }
    server {
        listen 8002;
        access_log /var/log/nginx/servico2.log main;
        ...
    }
    

    E rode tail -f em cada arquivo para ver a alternância.

  • Evite “localhost” ambíguo: não é o seu problema aqui, mas por boa prática você pode explicitar IPv4:

    upstream services {
        server 127.0.0.1:8001;
        server 127.0.0.1:8002;
    }
    

Por que isso acontece?

  • O balanceamento é por requisição, mas se há uma conexão HTTP/1.1 já aberta para um upstream, o NGINX pode reutilizá-la, e então várias requisições acabam indo pelo mesmo túnel TCP para o mesmo backend.
  • Navegadores mantêm conexões abertas por desempenho. Em um lab simples, isso dá a impressão de “não balancear”.
  • Ao fechar a conexão a cada requisição (HTTP/1.0 ou Connection: close), você força o NGINX a selecionar novamente um servidor no upstream, revelando o round-robin.

Em resumo: seu setup está correto; o “não alternar” vem do keep-alive. Adote a opção 1 ou 2 acima e você verá o load balancer distribuir as requisições entre 8001 e 8002 ao recarregar a página.

Alura Conte com o apoio da comunidade Alura na sua jornada. Abraços e bons estudos!