Há alguns dias, eu me deparei com uma mensagem de erro interessante no Nginx.
[crit] 12889#0: *32401195 connect() to 127.0.0.1:80 failed (99: Cannot assign requested address) while connecting to upstream
Minha configuração foi muito simples. Isso foi um proxy Nginx que fez toda a criptografia SSL e enviou o tráfego para instância de Varnish, sendo executado em port :80 em localhost. A grande questão aqui é que foi um tráfego bastante elevado de proxy Nginx.
Mesmo com keepalive ativado no upstream do nginx, o erro apareceu. Mas o que isso significa?
Portas TCP e limites
É bom saber uma coisa ou duas sobre redes, além de apenas servidores, de vez em quando. O problema ocorreu porque o servidor não poderia ter uma porta TCP livre rápido o suficiente para fazer a conexão com 127.0.0.1.
$ ss -s Total: 3130 (kernel 3431) TCP: 51582 (estab 2866, closed 48611, orphaned 92, synrecv 0, timewait 48611/0), ports 35279
A ferramenta ss oferece estatísticas sobre soquetes/portas no servidor. Neste caso, eu tinha 51.582 sessões TCP em uso (tanto ativas, fechadas, à espera de serem fechada, …).
Um servidor normal tem aproximadamente 28.000 portas TCP possíveis que podem ser usadas para fazer uma conexão TCP para um sistema remoto (ou local). Tudo o que fala por meio de um endereço IP irá escolher uma porta livre dessas para servir como porta de origem para a conexão de saída. Esse intervalo de porta é definido pelo parâmetro sysctl ip_local_port_range.
$ cat /proc/sys/net/ipv4/ip_local_port_range 32768 61000 $ sysctl net.ipv4.ip_local_port_range net.ipv4.ip_local_port_range = 32768 61000
O formato é porta “minimum maximum“. Assim, 61.000-32.768 = 28 232 portas-fonte disponíveis.
Um proxy SSL Nginx que se conecta a uma instância Varnish rodando em localhost será parecido com isto em sua netstat.
$ netstat -anp | grep 127.0.0.1 ... tcp 0 0 127.0.0.1:37713 127.0.0.1:80 TIME_WAIT -
O principal tópico aqui é a conexão de fonte de 127.0.0.1:37713 que se conecta ao seu endpoint 127.0.0.1:80. Para cada origem de conexão, uma nova fonte porta TCP é selecionada a partir do intervalo no parâmetro ip_local_port_range.
A combinação de um IP de origem, porta de origem, IP de destino e destino IP deve ser única. Isso é o que é chamado um quadruplet em termos de rede. Você provavelmente não pode (facilmente) mudar o IP de origem. A porta de origem é escolhida de forma dinâmica. Isso só deixa a o IP de destino e a porta de destino livres para brincar.
Resolvendo a limitação da porta de origem
Há algumas correções fáceis. Primeiro, o ip_local_port_range pode ser aumentado em uma máquina Linux (para obter mais material de leitura, ver aumentar o intervalo ip_local_port_range de portas TCP no Linux).
$ echo 15000 64000 > /proc/sys/net/ipv4/ip_local_port_range
Isso efetivamente aumenta o intervalo de portas totais do padrão de 28.232 para 49.000 portas.
Se isso não for suficiente, você pode adicionar mais IPs de destino para se conectar. Lembre-se de que cada conexão consiste em 4 partes (chamadas quadruplets) com porta de origem e IP de origem, IP de destino e porta de destino. Se você não pode mudar a porta de origem ou IP, basta alterar os IPs de destino.
Considere este tipo de definição para o upstream em Nginx;
upstream varnish { server 127.0.0.1:80; }
Essa definição pode ser usada em suas configurações nginx com a diretiva proxy_pass.
server { listen 443; ... location / { proxy_pass http://varnish; ... } }
Agora, se você sabe que cada servidor tem geralmente 2 IPs ou mais, é muito fácil adicionar mais quadriplets à sua pilha de rede, fazendo uma adição ao seu IP Nginx upstream. Você já adicionou 127.0.0.1, mas o servidor terá um outro IP (será público ou DHCP IP) que você pode adicionar com segurança também, se o seu servidor web se liga a todas as portas.
upstream varnish { server 127.0.0.1:80; server 31.193.180.217:80; server 10.50.5.1:80; ... }
Cada IP que você adicionar em seu upstream está efetivamente adicionando 49.000 portas locais para a sua pilha de rede. Você pode até adicionar IPs locais não-roteáveis para o servidor, como aliases de interface, apenas para usar como novos IPs de destino para as suas configurações de proxy.
***
Mattias Geniar faz parte do time de colunistas internacionais do iMasters. A tradução do artigo é feita pela redação iMasters, com autorização do autor, e você pode acompanhar o artigo em inglês no link: https://ma.ttias.be/nginx-cannot-assign-requested-address-for-upstream/