Dans ce billet, je souhaite discuter d'une erreur de codage courante qui peut entraîner l'épuisement ou, du moins, l'épuisement sérieux du nombre de clones de périphériques stcp disponibles pour la création de sockets TCP.
Chaque appel à la fonction socket entraîne la création par STCP d'un nouveau clone du périphérique stcp. Le nombre maximal de clones pouvant être créés est contrôlé par le champ clone_limit dans l'entrée devices.tin.
/ =nom stcp.m17
=nom_module m17
=type_périphérique flux
=nom_liste_accès stcp_access
=pilote_flux stcp
=clone_limit 5120
=comment Fournit l'API TCP
|
Vous pouvez voir combien de clones sont actuellement utilisés en vidant la structure du périphérique dans analyze_system et en consultant la valeur clone_count. Si clone_count est égal à clone_limit, les appels à la fonction socket renverront une erreur e$clone_limit_exceeded : « La limite de clones pour le périphérique a été dépassée ».
comme : match clone ; dump_dvt -name stcp.m17
clone_limit : 5120
clone_count : 42
cloned_from : -27271
remote_clone_limit : 0
|
En général, l'appel de socket qui crée le périphérique cloné est suivi soit d'un connect ou bind et listen . À ce stade, vous pouvez voir une entrée correspondante lorsque vous exécutez la commande « netstat ».
netstat -numeric -all_sockets Connexions actives (y compris les serveurs) Proto Recv-Q Send-Q Adresse locale Adresse étrangère (état) tcp 0 0 172.16.124.217:23 192.168.109.22:50038 ESTABLISHED tcp 0 0 172.16.124.217:22 172.16.124.24:54987 ESTABLISHED 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 ESTABLISHED tcp 0 0 172.16.124.217:22 172.16.124.50:17421 ESTABLISHED tcp 0 0 172.16.124.217:22 172.16.124.50:17658 ESTABLISHED tcp 0 0 *:23 *:* LISTEN 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 ESTABLISHED 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 ESTABLISHED tcp 0 0 *:3001 *:* LISTEN tcp 0 0 *:3002 *:* LISTEN tcp 0 0 *:3003 *:* LISTEN tcp 0 0 *:4000 *:* LISTEN tcp 0 0 172.16.124.217:4000 172.16.124.78:1024 ESTABLISHED tcp 0 0 172.16.124.217:4000 172.16.124.227:1025 ESTABLISHED tcp 0 0 *:4001 *:* LISTEN tcp 0 0 *:4002 *:* LISTEN tcp 0 0 *:4003 *:* LISTEN tcp 0 0 *:4004 *:* LISTEN tcp 0 0 *:22 *:* LISTEN tcp 0 0 *:4005 *:* LISTEN tcp 0 0 *:4006 *:* ÉCOUTE tcp 0 0 172.16.124.217:4006 172.16.124.203:49231 ÉTABLI tcp 0 0 *:4007 *:* ÉCOUTE tcp 0 0 *:4008 *:* LISTEN tcp 0 0 *:4009 *:* LISTEN tcp 0 0 172.16.124.217:4008 172.16.124.203:49262 ESTABLISHED 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 *:* ÉCOUTE tcp 0 0 *:139 *:* ÉCOUTE tcp 0 0 10.20.1.1:53495 10.20.1.9:48879 ÉTABLI tcp 0 0 10.20.1.1:61703 10.20.1.3:48879 ESTABLISHED tcp 0 0 10.20.1.1:61707 10.20.1.3:48879 ESTABLISHED tcp 0 0 10.20.1.1:61705 10.20.1.9:48879 ÉTABLI tcp 0 0 10.20.1.1:61709 10.20.1.9:48879 ÉTABLI tcp 0 0 10.20.1.1:61710 10.20.1.9:48879 ÉTABLI tcp 0 0 172.16.124.217:61789 172.16.124.203:4000 ÉTABLI tcp 0 400 172.16.124.217:22 172.16.124.50:17674 ESTABLISHED |
Si vous comptez le nombre de lignes, vous verrez qu'il y en a plus de 42, car toutes les entrées affichées par netstat n'utilisent pas un clone de périphérique stcp. Par exemple, les connexions OSL et les connexions X25_cpc utilisées avec le NIO. Consultez socket_count.cm pour plus de détails.
Si un appel socket est effectué sans connexion ou liaison, ou si la liaison échoue, vous pouvez créer le problème inverse : la valeur de clone_count est supérieure au nombre d'entrées affiché par netstat.
comme : clone de correspondance ; dump_dvt -nom stcp.m17
limite de clonage : 5120
clone_count : 4131
cloned_from : -23179
remote_clone_limit : 0
as :
|
Je ne reproduis pas ici la sortie netstat, mais croyez-moi, elle n'a pas changé par rapport à l'exemple précédent.
Cette situation, à savoir un clone supplémentaire (4131 – 42) et apparemment non pris en compte, du périphérique STCP a été créée par le fragment de code suivant. Le code appelle la fonction socket suivie de la fonction bind. Si la liaison échoue, il boucle. De nombreuses applications ajouteraient un minuteur pour attendre 1, 60 ou 300 secondes et réessayer, ce qui ne fait que retarder l'inévitable, en supposant bien sûr que la condition à l'origine de l'erreur ne disparaisse pas.
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;
}
}
|
L'erreur la plus courante est qu'un autre processus est déjà lié au port demandé. Quelle que soit la raison de l'erreur, la solution consiste à fermer le socket après avoir signalé l'erreur de liaison.
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;
}
}
|
Cet article traitait de l'atteinte de la limite clone_limit en raison d'une erreur de codage, mais que se passe-t-il s'il n'y a pas d'erreur, si l'environnement d'application utilise réellement tous ces périphériques clones ? Dans ce cas, en supposant que vous n'ayez pas atteint la limite système de 16 000, vous pouvez augmenter la limite. Vous devez mettre à jour le champ clone_limit du périphérique stcp dans le fichier devices.tin et recréer le fichier devices.table. Si vous utilisez une version 17.1 ou ultérieure, vous pouvez utiliser la commande update_device_info pour augmenter la limite pour le démarrage actuel et vous fier au fichier devices.table mis à jour pour le prochain démarrage. Sur les versions antérieures à 17.1, votre seule option réelle est de redémarrer. Vous devez définir la limite à une valeur qui correspond à vos besoins actuels et à la croissance prévue ; vous ne devez pas simplement augmenter la limite à 16 000. Même si vous n'avez pas actuellement de bogue d'application qui consomme des périphériques clones, rien ne garantit que vous n'en aurez pas à l'avenir. Une application qui consomme tous les périphériques clones disponibles consommera également une grande quantité de mémoire de flux, ce qui aura un impact négatif sur les connexions TCP existantes.
