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 socket resulta na criação de um novo clone do dispositivo stcp pelo STCP. O número máximo de clones que podem ser criados é controlado pelo campo clone_limit na entrada devices.tin.
/ =nome stcp.m17
=nome_do_módulo m17
=tipo_de_dispositivo streams
=nome_da_lista_de_acesso stcp_access
=driver_de_streams stcp
=limite_clone 5120
=comentário Fornece API TCP
|
Você pode ver quantos clones estão atualmente em uso despejando a estrutura do dispositivo em analyze_system e verificando o valor clone_count. Se clone_count for igual a clone_limit, as chamadas para a função socket retornarão um erro e$clone_limit_exceeded: “O limite de clones para o dispositivo foi excedido”.
como: clone de correspondência; dump_dvt -name stcp.m17
clone_limit: 5120
contagem_de_clones: 42
cloned_from: -27271
limite_de_clones_remotos: 0
|
Em geral, a chamada ao soquete que cria o dispositivo clone é seguida por um chamada connect ou bind e listen . Nesse ponto, você pode ver uma entrada correspondente ao executar o “comando netstat”.
netstat -numeric -all_sockets Conexões ativas (incluindo servidores) Proto Recv-Q Send-Q Endereço local Endereço externo (estado) tcp 0 0 172.16.124.217:23 192.168.109.22:50038 ESTABLECIDA tcp 0 0 172.16.124.217:22 172.16.124.24:54987 ESTABLECIDA 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 ESTABELECIDA tcp 0 0 172.16.124.217:22 172.16.124.50:17421 ESTABLECIDA tcp 0 0 172.16.124.217:22 172.16.124.50:17658 ESTABELECIDA tcp 0 0 *:23 *:* ESCOLHA tcp 0 0 *:6666 *:* LISTEN tcp 0 0 *:21 *:* LISTEN tcp 0 0 *:3000 *:* LISTEN tcp 0 0 *:7 *:* LISTEN tcp 0 0 *:9 *:* LISTEN tcp 0 0 *:13 *:* LISTEN tcp 0 0 *:19 *:* LISTEN tcp 0 0 *:37 *:* LISTEN tcp 0 0 *:901 *:* LISTEN tcp 0 0 *:1414 *:* LISTEN tcp 0 0 *:81 *:* LISTEN 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 ESTABLECIDA 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 ESTABELECIDA tcp 0 0 *:3001 *:* ESCOLHA tcp 0 0 *:3002 *:* ESCOLHA tcp 0 0 *:3003 *:* LISTEN tcp 0 0 *:4000 *:* LISTEN tcp 0 0 172.16.124.217:4000 172.16.124.78:1024 ESTABLECIDA tcp 0 0 172.16.124.217:4000 172.16.124.227:1025 ESTABELECIDA tcp 0 0 *:4001 *:* ESCOLHA tcp 0 0 *:4002 *:* ESCOLHA tcp 0 0 *:4003 *:* LISTEN tcp 0 0 *:4004 *:* LISTEN tcp 0 0 *:22 *:* LISTEN tcp 0 0 *:4005 *:* LISTEN tcp 0 0 *:4006 *:* LISTEN tcp 0 0 172.16.124.217:4006 172.16.124.203:49231 ESTABLISHED tcp 0 0 *:4007 *:* LISTEN tcp 0 0 *:4008 *:* LISTEN tcp 0 0 *:4009 *:* LISTEN tcp 0 0 172.16.124.217:4008 172.16.124.203:49262 ESTABLECIDA tcp 0 0 *:4010 *:* LISTEN tcp 0 0 *:4011 *:* LISTEN tcp 0 0 *:4012 *:* LISTEN tcp 0 0 *:4013 *:* LISTEN tcp 0 0 *:4014 *:* LISTEN tcp 0 0 *:4015 *:* LISTEN tcp 0 0 *:80 *:* LISTEN tcp 0 0 *:9182 *:* LISTEN tcp 0 0 *:445 *:* LISTEN tcp 0 0 *:139 *:* LISTEN tcp 0 0 10.20.1.1:53495 10.20.1.9:48879 ESTABLISHED tcp 0 0 10.20.1.1:61703 10.20.1.3:48879 ESTABELECIDA tcp 0 0 10.20.1.1:61707 10.20.1.3:48879 ESTABELECIDA tcp 0 0 10.20.1.1:61705 10.20.1.9:48879 ESTABELECIDA tcp 0 0 10.20.1.1:61709 10.20.1.9:48879 ESTABELECIDA tcp 0 0 10.20.1.1:61710 10.20.1.9:48879 ESTABELECIDA tcp 0 0 172.16.124.217:61789 172.16.124.203:4000 ESTABELECIDA tcp 0 400 172.16.124.217:22 172.16.124.50:17674 ESTABELECIDA |
Se você contar o número de linhas, verá mais de 42, isso porque nem todas as entradas mostradas pelo netstat usam um clone de dispositivo stcp. Por exemplo, conexões OSL e conexões X25_cpc usadas com o NIO. Consulte socket_count.cm para obter mais detalhes.
Se uma chamada de soquete for feita sem uma conexão ou ligação, ou se a ligação falhar, você pode criar o problema oposto: o valor de clone_count será maior do que o número de entradas mostrado pelo netstat.
como: clone de correspondência; dump_dvt -nome stcp.m17
clone_limit: 5120
clone_count: 4131
cloned_from: -23179
limite_de_clones_remotos: 0
como:
|
Não estou incluindo a saída do netstat novamente, mas acredite, ela não mudou em relação ao exemplo anterior.
Essa situação, um clone extra (4131 – 42) e aparentemente não contabilizado do dispositivo STCP, foi criada pelo seguinte fragmento de código. O código chama a função socket seguida pela função bind. Se a ligação falhar, ele entra em loop. Muitos aplicativos adicionariam um temporizador para esperar 1, 60 ou 300 segundos e tentar novamente, o que apenas atrasa o inevitável, supondo, é claro, que a condição que causa o erro não desapareça.
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 à porta solicitada. Independentemente do motivo do erro, a solução é fechar o soquete após relatar o erro de vinculaçã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;
}
}
|
Esta publicação foi sobre atingir o limite clone_limit devido a um erro de codificação, mas e se não houver erro, e se o ambiente da aplicação estiver realmente a utilizar todos esses dispositivos clone? Bem, então, assumindo que não atingiu o limite do sistema de 16.000, pode aumentar o limite. Você precisa atualizar o campo clone_limit do dispositivo stcp no arquivo devices.tin e recriar o devices.table. Se você estiver na versão 17.1 ou posterior, pode usar o comando update_device_info para aumentar o limite para a inicialização atual e confiar no devices.table atualizado para cuidar da próxima inicialização. Nas versões anteriores à 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 simplesmente aumentar o limite para 16.000. Mesmo que você não tenha um bug de aplicativo que esteja consumindo dispositivos clone agora, não há garantia de que você não terá um no futuro. Um aplicativo que está consumindo todos os dispositivos clone disponíveis também consumirá uma grande quantidade de memória de fluxos, e esgotar a memória de fluxos afetará negativamente as conexões TCP existentes.
