BLOG | NGINX

Superando a exaustão efêmera de portas no NGINX e NGINX Plus

NGINX-Parte-de-F5-horiz-preto-tipo-RGB
Miniatura de Kevin Jones
Kevin Jones
Publicado em 19 de abril de 2016

NGINX e NGINX Plus são balanceadores de carga HTTP , TCP e UDP extremamente poderosos. Eles são muito eficientes em fazer proxy de grandes rajadas de solicitações e manter um grande número de conexões simultâneas. Mas essas características tornam o NGINX e o NGINX Plus particularmente sujeitos ao esgotamento efêmero de portas – uma condição em que novas conexões não podem ser criadas porque o sistema operacional ficou sem os números de portas alocados para estabelecer novos soquetes locais. (O esgotamento temporário de portas se aplica a ambos os produtos, mas, por uma questão de brevidade, nos referiremos apenas ao NGINX Plus no restante deste blog.)

Neste blog, revisamos os componentes de uma conexão TCP e como seu conteúdo é decidido antes que uma conexão seja estabelecida. Em seguida, mostramos como determinar quando o NGINX Plus está sendo afetado pelo esgotamento de porta efêmera. Por fim, discutimos estratégias para combater essas limitações usando ajustes do kernel Linux e diretivas NGINX Plus.

Uma breve visão geral dos soquetes de rede

Quando uma conexão é estabelecida via TCP, um soquete é criado no host local e no remoto. Esses soquetes são então conectados para criar um par de soquetes, que é descrito por uma tupla quádrupla exclusiva que consiste no endereço IP local e na porta, juntamente com o endereço IP remoto e a porta.

O endereço IP remoto e a porta 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 a partir de um intervalo definido disponibilizado pelo sistema operacional. A porta é associada ao cliente somente durante a conexão e, portanto, é chamada de efêmera . Quando a conexão é encerrada, a porta efêmera fica disponível para ser reutilizada.

Reconhecendo a exaustão efêmera do porto

Conforme mencionado na introdução, o NGINX Plus está sujeito, por natureza, ao esgotamento efêmero de portas e aos problemas que ele causa. Quando o NGINX Plus envia uma solicitação por proxy para um servidor upstream, ele é o cliente no processo de criação de soquete descrito acima, e seu comportamento padrão é vincular o soquete para a solicitação com proxy automaticamente a um endereço IP local e uma porta efêmera disponível no host onde ele está sendo executado. Se a taxa de conexão for alta, de modo que os soquetes que estão sendo estabelecidos sejam movidos para um estado de espera mais rápido do que os soquetes abertos existentes estão sendo fechados, então, eventualmente, as portas disponíveis serão esgotadas e novos soquetes não poderão ser criados. Isso resulta em erros tanto no sistema operacional quanto no NGINX Plus. Aqui está um exemplo do erro resultante no log de erros do NGINX Plus.

2016/03/18 09:08:37 [crit] 1888#1888: *13 connect() para 10.2.2.77:8081 falhou (99: Não é possível atribuir o endereço solicitado ) ao conectar-se ao upstream, cliente: 10.2.2.42, servidor: , solicitação: "GET / HTTP/1.1", upstream: "http://10.2.2.77:8081/", host: "10.2.2.77"

O esgotamento dos portos também causa um pico de500 erros originados pelo NGINX Plus e não pelo servidor upstream. Aqui está 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 "-" "curvatura/7.35.0"

Para verificar o número de soquetes no estado TIME-WAIT no seu servidor NGINX Plus, execute o seguinte comando ss no shell do Linux. O exemplo mostra que há 143 soquetes abertos com status TIME-WAIT . No exemplo, obtemos a contagem usando o comando wc para listar o número de linhas na saída do comando.

# ss -a | grep TEMPO-ESPERA | wc -l143

Ajustando o Kernel para Aumentar o Número de Portas Efêmeras Disponíveis

Uma maneira de reduzir o esgotamento temporário de portas é com a configuração net.ipv4.ip_local_port_range do kernel Linux. O intervalo padrão é mais comumente de 32.768 a 61.000.

Se você perceber que está ficando sem portas efêmeras, alterar o intervalo do 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 postagem do blog Ajustando o NGINX para desempenho .

Habilitando conexões Keepalive no NGINX Plus

Outra maneira de reduzir o esgotamento temporário de portas é habilitar conexões keepalive entre o NGINX Plus e os servidores upstream. Na implementação mais simples do HTTP, um cliente abre uma nova conexão, grava a solicitação, lê a resposta e fecha a conexão para liberar os recursos associados.

Uma conexão keepalive é mantida aberta depois que o cliente lê a resposta, para que ela possa ser reutilizada para solicitações subsequentes.

Use a diretiva keepalive para habilitar conexões keepalive do NGINX Plus para servidores upstream, definindo o número máximo de conexões keepalive ociosas para servidores upstream que são preservadas no cache de cada processo de trabalho. Quando esse número é excedido, as conexões menos utilizadas recentemente são fechadas. Sem keepalives, você adiciona mais sobrecarga e é ineficiente tanto com conexões quanto com portas efêmeras.

A configuração de exemplo a seguir informa ao NGINX Plus para manter pelo menos 128 conexões keepalive com os servidores definidos no bloco upstream chamado backend .

backend upstream { servidor 10.0.0.100:1234;
servidor 10.0.0.101:1234;
keepalive 128;
}

Ao habilitar conexões keepalive para seus servidores upstream, você também deve usar a diretiva proxy_http_version para informar ao NGINX Plus para usar o HTTP versão 1.1, e a diretiva proxy_set_header para remover quaisquer cabeçalhos chamados Connection . Ambas as diretivas podem ser colocadas nos blocos de configuração http , server ou location .

proxy_http_version 1.1; proxy_set_header Conexão "";

Ligação dinâmica de conexões a uma lista definida de endereços IP locais

Otimizar o kernel e habilitar conexões keepalive proporcionam muito mais controle sobre a disponibilidade e o uso de portas efêmeras, mas há certas situações em que essas alterações não são suficientes para combater o uso excessivo de portas efêmeras. Nesse caso, podemos empregar algumas diretivas e parâmetros do NGINX Plus que nos permitem vincular uma porcentagem de nossas conexões a endereços IP locais estáticos. Isso efetivamente multiplica o número de portas efêmeras disponíveis pelo número de endereços IP definidos na configuração. Para fazer 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 para 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" ) que é criptografada 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 dos quais contém uma porcentagem dos hashes. Aqui dividimos a tabela em 10 baldes do mesmo tamanho, mas podemos criar qualquer número de baldes e eles não precisam ser todos do mesmo tamanho. (A porcentagem do último intervalo é sempre representada pelo asterisco [ * ] em vez de um número específico, porque o número de hashes pode não ser divisível uniformemente nas porcentagens especificadas.)

O intervalo de valores de hash possíveis é de 0 a 4294967295, então, no nosso caso, cada bucket contém cerca de 429496700 valores (10% do total): o primeiro bucket contém valores de 0 a 429496700, o segundo bucket contém valores 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 cai no quarto intervalo, então a variável $split_ip é definida dinamicamente como 10.0.0.213 nesse caso.

http { backend upstream { servidor 10.0.0.100:1234; servidor 10.0.0.101:1234; } servidor { # ... localização / { # ... 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 Linux para o número de portas efêmeras proporciona disponibilidade e uso mais eficientes. Habilitar conexões keepalive do NGINX Plus para seus servidores upstream torna o consumo de portas efêmeras mais eficiente. Por fim, usar as diretivas split_clients e proxy_bind na configuração do NGINX Plus permite que você vincule dinamicamente conexões de saída a uma lista definida de endereços IP locais, aumentando muito o número de portas efêmeras disponíveis para o NGINX Plus.

Para experimentar o NGINX Plus, comece hoje mesmo seu teste gratuito de 30 dias ou entre em contato conosco para discutir seus casos de uso.


"Esta postagem do blog pode fazer referência a produtos que não estão mais disponíveis e/ou não têm mais suporte. Para obter as informações mais atualizadas sobre os produtos e soluções F5 NGINX disponíveis, explore nossa família de produtos NGINX . O NGINX agora faz parte do F5. Todos os links anteriores do NGINX.com redirecionarão para conteúdo semelhante do NGINX no F5.com."