Pular para o conteúdo principal

Neste post, desejo discutir um erro de codificação comum que pode resultar no esgotamento ou, pelo menos, no esgotamento sério do número disponível de clones de dispositivos stcp para uso na criação de soquetes TCP.

Cada chamada para a função soquete resulta em STCP criando um novo clone do dispositivo stcp. O número máximo de clones que podem ser criados é controlado pelo campo clone_limite na entrada dos dispositivos.tin.

/ =nome stcp.m17
     =module_name m17
     =device_type streams
     =access_list_name stcp_access
     =streams_driver stcp
     =clone_limite 5120
     =comentário Fornece TCP API

Você pode ver quantos clones estão em uso atualmente, despejando a estrutura do dispositivo no sistema de análise e olhando para o valor da contagem de clones. Se a contagem de clones for igual ao limite de clones, as chamadas para a função de socket retornarão um e$clone_limit_excedido: erro "O limite de clone para o dispositivo foi excedido".

como: match clone; dump_dvt -nome stcp.m17
limite_de_clone: 5120
clone_count:       42
cloned_from: -27271
remote_clone_limit: 0

Em geral, a chamada do soquete que cria o dispositivo clone é seguida ou por um conectar chamada ou amarrar e ouvir chamadas. Nesse momento você pode ver uma entrada correspondente quando executa o "comando netstat".

netstat -numeric -all_sockets
Conexões ativas (incluindo servidores)
Proto Recv-Q Send-Q Endereço Local Endereço Estrangeiro (Estado)
tcp 0 0 172.16.124.217:23 192.168.109.22:50038 ESTABELECIDO
tcp 0 0 172.16.124.217:22 172.16.124.24:54987 ESTABELECIDO
tcp 0 0 10.20.1.1:37 10.20.1.26:1528 TIME_WAIT
tcp 0 0 10.20.1.1:37 10.20.1.27:1579 TIME_WAIT
tcp 0 0 172.16.124.217:61780 192.168.109.22:23 ESTABELECIDO
tcp 0 0 172.16.124.217:22 172.16.124.50:17421 ESTABELECIDO
tcp 0 0 172.16.124.217:22 172.16.124.50:17658 ESTABELECIDO
tcp 0 0 *:23 *:* OUÇA
tcp 0 0 *:6666 *:* OUÇA
tcp 0 0 *:21 *:* OUÇA
tcp 0 0 *:3000 *:* OUÇA
tcp 0 0 *:7 *:* OUÇA
tcp 0 0 *:9 *:* OUÇA
tcp 0 0 *:13 *:* OUÇA
tcp 0 0 *:19 *:* OUÇA
tcp 0 0 *:37 *:* OUÇA
tcp 0 0 *:901 *:* OUÇA
tcp 0 0 *:1414 *:* OUÇA
tcp 0 0 *:81 *:* OUÇA
tcp 0 0 10.20.1.1:37 10.20.1.9:3633 TIME_WAIT
tcp 0 50 10.10.1.1:52653 10.10.1.200:3001 ESTABELECIDO
tcp 0 0 10.10.1.1:52624 10.10.1.200:3001 FIN_WAIT_1
tcp 0 0 10.20.1.1:61704 10.20.1.3:48879 ESTABELECIDO
tcp 0 0 *:3001 *:* OUÇA
tcp 0 0 *:3002 *:* OUÇA
tcp 0 0 *:3003 *:* OUÇA
tcp 0 0 *:4000 *:* OUÇA
tcp 0 0 172.16.124.217:4000 172.16.124.78:1024 ESTABELECIDO
tcp 0 0 172.16.124.217:4000 172.16.124.227:1025 ESTABELECIDO
tcp 0 0 *:4001 *:* OUÇA
tcp 0 0 *:4002 *:* OUÇA
tcp 0 0 *:4003 *:* OUÇA
tcp 0 0 *:4004 *:* OUÇA
tcp 0 0 *:22 *:* OUÇA
tcp 0 0 *:4005 *:* OUÇA
tcp 0 0 *:4006 *:* OUÇA
tcp 0 0 172.16.124.217:4006 172.16.124.203:49231 ESTABELECIDO
tcp 0 0 *:4007 *:* OUÇA
tcp 0 0 *:4008 *:* OUÇA
tcp 0 0 *:4009 *:* OUÇA
tcp 0 0 172.16.124.217:4008 172.16.124.203:49262 ESTABELECIDO
tcp 0 0 *:4010 *:* OUÇA
tcp 0 0 *:4011 *:* OUÇA
tcp 0 0 *:4012 *:* OUÇA
tcp 0 0 *:4013 *:* OUÇA
tcp 0 0 *:4014 *:* OUÇA
tcp 0 0 *:4015 *:* OUÇA
tcp 0 0 *:80 *:* OUÇA
tcp 0 0 *:9182 *:* OUÇA
tcp 0 0 *:445 *:* OUÇA
tcp 0 0 *:139 *:* OUÇA
tcp 0 0 10.20.1.1:53495 10.20.1.9:48879 ESTABELECIDO
tcp 0 0 10.20.1.1:61703 10.20.1.3:48879 ESTABELECIDO
tcp 0 0 10.20.1.1:61707 10.20.1.3:48879 ESTABELECIDO
tcp 0 0 10.20.1.1:61705 10.20.1.9:48879 ESTABELECIDO
tcp 0 0 10.20.1.1:61709 10.20.1.9:48879 ESTABELECIDO
tcp 0 0 10.20.1.1:61710 10.20.1.9:48879 ESTABELECIDO
tcp 0 0 172.16.124.217:61789 172.16.124.203:4000 ESTABELECIDO
tcp 0 400 172.16.124.217:22 172.16.124.50:17674 ESTABELECIDO

Se você contar o número de linhas você verá mais de 42, isto é, porque nem toda entrada mostrada pela netstat usa um clone de dispositivo stcp. Por exemplo, as conexões OSL e as conexões X25_cpc usadas com o NIO. Dê uma olhada em socket_count.cm para mais detalhes.

Se uma chamada de soquete é feita sem conexão ou ligação ou a ligação falha, você pode criar o problema oposto, o valor da contagem de clones é maior do que o número de entradas mostrado pela netstat.

como: match clone; dump_dvt -nome stcp.m17
limite_de_clone: 5120
clone_count:       4131
cloned_from: -23179
remote_clone_limit: 0
como:

Não estou incluindo novamente a saída netstat, mas acredite em mim, ela não mudou em relação ao exemplo anterior.

Esta situação, um extra (4131 - 42) e aparentemente não contabilizado, clones de dispositivos STCP foi criado pelo seguinte fragmento de código. O código chama a função socket seguido da função bind. Se o bind falhar, ele faz loop. Muitas aplicações acrescentariam um timer para esperar 1, 60, ou 300 segundos e tentar novamente, o que apenas retarda o inevitável, assumindo, é claro, que a condição que causa o erro não desaparece.

tryAgain = 1;
while (tryAgain)
  {
  if ((socks0 = socket (AF_INET, SOCK_STREAM, 0)) < 0)
     {
     if (debugFlag)
        perror ("badService: can't create listening socket");
     }
  else {
/* build a sockaddr structure holding the address we will bind to.
   The IP address is INADDR_ANY meaning we will listen on all active
   IP addresses */

     bzero ( (char *) &serv_addr, sizeof (serv_addr));
     serv_addr.sin_family        = AF_INET;
     serv_addr.sin_addr.s_addr   = htonl (INADDR_ANY);
     serv_addr.sin_port          = htons (portNumber);

/* now bind to the address and port */
     if (bind (socks0, (struct sockaddr *) &serv_addr,
                                      sizeof (serv_addr)) < 0)
        {
        if (debugFlag)
           perror ("badService: can't bind address, trying again");
        }
     else
        tryAgain = 0;
     }
   }

O erro mais comum é que outro processo já está vinculado ao porto solicitado. Independentemente do motivo do erro, a solução é fechar o soquete após relatar o erro de ligação.

tryAgain = 1;
while (tryAgain)
  {
  if ((socks0 = socket (AF_INET, SOCK_STREAM, 0)) < 0)
     {
     if (debugFlag)
        perror ("goodService: can't create listening socket");
     }
  else {
/* build a sockaddr structure holding the address we will bind to.
   The IP address is INADDR_ANY meaning we will listen on all active
   IP addresses */

     bzero ( (char *) &serv_addr, sizeof (serv_addr));
     serv_addr.sin_family        = AF_INET;
     serv_addr.sin_addr.s_addr   = htonl (INADDR_ANY);
     serv_addr.sin_port          = htons (portNumber);

/* now bind to the address and port */
     if (bind (socks0, (struct sockaddr *) &serv_addr,
                                      sizeof (serv_addr)) < 0)
        {
        if (debugFlag)
           perror ("goodService: can't bind address, trying again");
        if (close (socks0) < 0)
           if (debugFlag)
              perror ("goodService: can't close old socket");
        }
     else
        tryAgain = 0;
     }
   }

 

Este post tem sido sobre alcançar o limite_de_clone por causa de um erro de codificação, mas e se não houver erro, e se o ambiente de aplicação estiver realmente usando todos esses dispositivos de clonagem. Bem, então, assumindo que você não atingiu o limite do sistema de 16.000, você pode aumentar o limite. Você precisa atualizar o campo clone_limite do dispositivo stcp no arquivo devices.tin e recriar os devices.table. Se você estiver em um lançamento 17.1 ou posterior, você pode usar o comando update_device_info para aumentar o limite para o boot atual e confiar no device.table atualizado para cuidar do próximo boot. Em lançamentos anteriores ao 17.1, sua única opção real é reiniciar. Você deve definir o limite para um valor que corresponda às suas necessidades atuais mais o crescimento esperado; você não deve apenas aumentar o limite para 16.000. Mesmo que você não tenha um bug de aplicação que esteja consumindo dispositivos clone agora, não há garantia de que você não terá um no futuro. Uma aplicação que está consumindo todos os dispositivos clones disponíveis também consumirá uma grande quantidade de memória de fluxos e a exaustão da memória de fluxos afetará negativamente as conexões TCP existentes.

© 2024 Stratus Technologies.