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.