NGINX e NGINX Plus são balanceadores de carga extremamente poderosos para HTTP, TCP e UDP. Eles são muito eficientes no encaminhamento de grandes picos de solicitações e na manutenção de um grande número de conexões simultâneas. No entanto, essas características tornam o NGINX e o NGINX Plus particularmente suscetíveis ao esgotamento de portas efêmeras — uma condição em que não é possível criar novas conexões porque o sistema operacional esgotou os números de porta alocados para estabelecer novos sockets locais. (O esgotamento de portas efêmeras se aplica a ambos os produtos, mas, para simplificar, mencionaremos apenas o NGINX Plus no restante deste blog.)
Neste blog, analisamos os componentes de uma conexão TCP e como seu conteúdo é definido antes que a conexão seja estabelecida. Em seguida, mostramos como determinar quando o NGINX Plus está sendo afetado pelo esgotamento de portas efêmeras. Por fim, discutimos estratégias para contornar essas limitações usando tanto ajustes no kernel do Linux quanto diretivas do NGINX Plus.
Uma breve visão geral dos sockets de rede
Quando uma conexão é estabelecida via TCP, um socket é criado tanto no host local quanto no remoto. Esses sockets são então conectados para formar um par de sockets, descrito por uma 4-tupla exclusiva composta pelo endereço IP e pela porta locais, bem como pelo endereço IP e pela porta remotos.
O endereço IP e a porta remotos pertencem ao lado do servidor da conexão e devem ser determinados pelo cliente antes mesmo que ele possa iniciar a conexão. Na maioria dos casos, o cliente escolhe automaticamente qual endereço IP local usar para a conexão, mas, às vezes, ele é escolhido pelo software que estabelece a conexão. Por fim, a porta local é selecionada aleatoriamente em um intervalo definido disponibilizado pelo sistema operacional. A porta fica associada ao cliente apenas durante a conexão e, por isso, é chamada de efêmera. Quando a conexão é encerrada, a porta efêmera fica disponível para reutilização.
Reconhecendo o esgotamento de portas efêmeras
Como mencionado na introdução, o NGINX Plus está, por natureza, sujeito ao esgotamento de portas efêmeras e aos problemas decorrentes disso. Quando o NGINX Plus encaminha uma solicitação por proxy para um servidor upstream, ele atua como cliente no processo de criação de soquete descrito acima, e seu comportamento padrão é vincular automaticamente o soquete da solicitação encaminhada a um endereço IP local e a uma porta efêmera disponível no host em que está sendo executado. Se a taxa de conexões for alta, de modo que os soquetes estabelecidos passem para um estado de espera mais rapidamente do que os soquetes abertos existentes sejam fechados, as portas disponíveis acabarão se esgotando e não será possível criar novos soquetes. Isso resulta em erros tanto no sistema operacional quanto no NGINX Plus. Veja a seguir um exemplo do erro resultante no log de erros do NGINX Plus.
2016/03/18 09:08:37 [crit] 1888#1888: *13 connect() to 10.2.2.77:8081 failed (99: Cannot assign requested address) while connecting to upstream, client: 10.2.2.42, server: , request: "GET / HTTP/1.1", upstream: "http://10.2.2.77:8081/", host: "10.2.2.77"O esgotamento de portas também causa um aumento nos erros 500 gerados pelo NGINX Plus, e não pelo servidor upstream. Veja um exemplo de entrada no log de acesso do NGINX Plus.
10.2.2.42 - - [18/Mar/2016:09:14:20 -0700] "GET / HTTP/1.1" 500 192 "-" "curl/7.35.0"Para verificar o número de sockets no estado TIME-WAIT em seu servidor NGINX Plus, execute o seguinte comando ss no shell do Linux. O exemplo mostra que há 143 sockets abertos com o estado TIME-WAIT. No exemplo, obtemos a contagem usando o comando wc para contar o número de linhas na saída do comando.
# ss -a | grep TIME-WAIT | wc -l143Ajustando o kernel para aumentar o número de portas efêmeras disponíveis
Uma forma de reduzir o esgotamento de portas efêmeras é usar a configuração do kernel Linux net.ipv4.ip_local_port_range. O intervalo padrão geralmente vai de 32768 a 61000.
Se você perceber que as portas efêmeras estão se esgotando, alterar o intervalo padrão para 1024 a 65000 é uma maneira prática de dobrar o número de portas efêmeras disponíveis para uso. Para obter mais informações sobre como alterar as configurações do kernel, consulte nossa publicação no blog Ajuste do NGINX para melhorar o desempenho.
Habilitando conexões keepalive no NGINX Plus
Outra maneira de reduzir o esgotamento de portas efêmeras é habilitar conexões persistentes entre o NGINX Plus e os servidores upstream. Na implementação mais simples do HTTP, um cliente abre uma nova conexão, envia a solicitação, lê a resposta e, em seguida, fecha a conexão para liberar os recursos associados.

Uma conexão keepalive é mantida aberta após o cliente ler a resposta, para que possa ser reutilizada em solicitações subsequentes.

Use a diretiva keepalive para habilitar conexões persistentes do NGINX Plus com servidores upstream, definindo o número máximo de conexões persistentes ociosas com servidores upstream que são mantidas no cache de cada processo worker. Quando esse número é excedido, as conexões usadas menos recentemente são fechadas. Sem conexões persistentes, você aumenta a sobrecarga e reduz a eficiência tanto das conexões quanto das portas efêmeras.
A configuração de exemplo a seguir instrui o NGINX Plus a manter pelo menos 128 conexões keepalive com os servidores definidos no bloco upstream chamado backend.
upstream backend { server 10.0.0.100:1234;
server 10.0.0.101:1234;
keepalive 128;
}Ao habilitar conexões keepalive com seus servidores upstream, você também deve usar a diretiva proxy_http_version para instruir o NGINX Plus a usar a versão 1.1 do HTTP e a diretiva proxy_set_header para remover todos os cabeçalhos chamados Connection. Ambas as diretivas podem ser inseridas nos blocos de configuração http, server ou location.
proxy_http_version 1.1; proxy_set_header Connection "";Vinculando conexões dinamicamente a uma lista definida de endereços IP locais
Otimizar o kernel e habilitar conexões keepalive proporciona muito mais controle sobre a disponibilidade e o uso de portas efêmeras, mas há situações em que essas alterações não são suficientes para combater o uso excessivo dessas portas. Nesse caso, podemos empregar algumas diretivas e parâmetros do NGINX Plus que nos permitem vincular uma porcentagem das nossas conexões a endereços IP locais estáticos. Isso efetivamente multiplica o número de portas efêmeras disponíveis pela quantidade de endereços IP definidos na configuração. Para isso, usamos as diretivas proxy_bind e split_clients.
Na configuração de exemplo abaixo, a diretiva proxy_bind no bloco location define o endereço IP local durante cada solicitação de acordo com o valor da variável $split_ip. Definimos essa variável dinamicamente com o valor gerado pelo bloco split_clients, que usa uma função hash para determinar esse valor.
O primeiro parâmetro da diretiva split_clients é uma string ("$remote_addr$remote_port") cujo hash é calculado usando uma função MurmurHash2 durante cada solicitação. O segundo parâmetro ($split_ip) é a variável que definimos dinamicamente com base no hash do primeiro parâmetro.
As instruções dentro das chaves dividem a tabela de hash em “buckets”, cada um contendo uma porcentagem dos hashes. Aqui, dividimos a tabela em 10 buckets do mesmo tamanho, mas podemos criar quantos buckets quisermos, e eles não precisam ter todos o mesmo tamanho. (A porcentagem do último bucket é sempre representada pelo asterisco [*] em vez de um número específico, pois a quantidade de hashes pode não ser divisível de maneira uniforme de acordo com as porcentagens especificadas.)
O intervalo de valores de hash possíveis vai de 0 a 4294967295, portanto, em nosso caso, cada bucket contém cerca de 429496700 valores (10% do total): o primeiro bucket contém os valores de 0 a 429496700, o segundo, de 429496701 a 858993400, e assim por diante. A variável $split_ip é definida como o endereço IP associado ao bucket que contém o hash da string $remote_addr$remote_port. Como exemplo específico, o valor de hash 150000000 está no quarto bucket; portanto, nesse caso, a variável $split_ip é definida dinamicamente como 10.0.0.213.
http { upstream backend {
server 10.0.0.100:1234;
server 10.0.0.101:1234;
}
server {
# ...
location / {
# ...
proxy_pass http://backend;
proxy_bind $split_ip;
proxy_set_header X-Forwarded-For $remote_addr;
}
}
split_clients "$remote_addr$remote_port" $split_ip { 10% 10.0.0.210; 10% 10.0.0.211; 10% 10.0.0.212; 10% 10.0.0.213; 10% 10.0.0.214; 10% 10.0.0.215; 10% 10.0.0.216; 10% 10.0.0.217; 10% 10.0.0.218; * 10.0.0.219; }
}Conclusão
Ajustar a configuração do kernel do Linux referente ao número de portas efêmeras proporciona maior eficiência na disponibilidade e no uso. Habilitar conexões keepalive do NGINX Plus com seus servidores upstream torna mais eficiente o consumo de portas efêmeras. Por fim, o uso das diretivas split_clients e proxy_bind na configuração do NGINX Plus permite vincular dinamicamente as conexões de saída a uma lista definida de endereços IP locais, aumentando significativamente o número de portas efêmeras disponíveis para o NGINX Plus.
Para experimentar o NGINX Plus, comece hoje mesmo sua avaliação gratuita de 30 dias ou entre em contato conosco para conversar sobre seus casos de uso.
Sobre o autor

Publicações relacionadas no blog

Como o F5 NGINX One aprimora o gerenciamento e a observabilidade
Descubra como o F5 NGINX One aprimora o gerenciamento e a observabilidade de ambientes híbridos e multicloud ao oferecer um console web centralizado baseado em SaaS, com insights em tempo real, conformidade automatizada e gerenciamento simplificado de configurações.

Do OpenAPI ao NGINX como gateway de API usando uma API declarativa
Descubra como transformar uma definição de esquema OpenAPI em uma configuração NGINX totalmente funcional, operando como um API Gateway com a segurança de um Web Application Firewall e um Portal do Desenvolvedor, usando uma abordagem declarativa de API.

Como gerenciar picos repentinos de tráfego e sobrecarga do servidor
Picos de tráfego e sobrecarga de servidores são preocupações sérias para varejistas online em qualquer época, mas especialmente durante a “Cyber Season” de compras de fim de ano. Detalhamos como você pode aproveitar as soluções de entrega de aplicações de nível de produção da NGINX para se preparar para aumentos repentinos de tráfego.

Distribuição segura de chaves privadas SSL com o NGINX
Descrevemos três maneiras progressivamente mais seguras de proteger chaves privadas SSL ao configurar o NGINX para processar tráfego HTTPS: permitir acesso de leitura apenas ao usuário root, criptografar as chaves com senhas armazenadas separadamente e distribuir as senhas a partir de um repositório central.
Agrupando solicitações de API em lotes com NGINX Plus e o módulo JavaScript do NGINX
O módulo JavaScript do NGINX lançado com o NGINX Plus R15 oferece suporte a subsolicitações, possibilitando uma classe totalmente nova de casos de uso para o NGINX Plus. Este exemplo completo também usa a API do NGINX Plus e os módulos de chave-valor para converter solicitações de API dos clientes em solicitações separadas para as APIs dos microsserviços que compõem um aplicativo.
Como superar o esgotamento de portas efêmeras no NGINX e no NGINX Plus
Confira dicas para evitar o esgotamento de portas efêmeras com ajustes no kernel do Linux, conexões keepalive e conexões vinculadas dinamicamente a endereços IP locais.