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 de socket entraîne la création par le STCP d'un nouveau clone du dispositif stcp. Le nombre maximum de clones pouvant être créés est contrôlé par le champ clone_limit dans l'entrée devices.tin.
/ =nom stcp.m17
=nom_du_module m17
=dispositif_type flux
=nom_liste_accès stcp_accès
=streams_driver stcp
=clone_limit 5120
=commentaire Fournit l'API TCP
|
Vous pouvez voir combien de clones sont actuellement utilisés en déchargeant la structure du dispositif dans analyze_system et en regardant la valeur clone_count. Si clone_count est égal à clone_limit, les appels à la fonction socket retourneront un e$clone_limit_exceeded : Erreur "La limite de clonage pour le dispositif a été dépassée".
comme : clone de correspondance ; dump_dvt -nom stcp.m17
clone_limit : 5120
clone_count : 42
cloné_de : -27271
remote_clone_limit : 0
|
En général, l'appel de socket qui crée le dispositif de clonage est suivi soit d'un se connecter appeler ou lier et écouter les appels. À 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 à l'étranger (état) tcp 0 0 172.16.124.217:23 192.168.109.22:50038 ÉTABLI tcp 0 0 172.16.124.217:22 172.16.124.24:54987 ÉTABLI 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 ÉTABLI tcp 0 0 172.16.124.217:22 172.16.124.50:17421 ÉTABLI tcp 0 0 172.16.124.217:22 172.16.124.50:17658 ÉTABLI tcp 0 0 *:23 *:* ÉCOUTER tcp 0 0 *:6666 *:* ÉCOUTER tcp 0 0 *:21 *:* ÉCOUTER tcp 0 0 *:3000 *:* ÉCOUTER tcp 0 0 *:7 *:* ÉCOUTER tcp 0 0 *:9 *:* ÉCOUTER tcp 0 0 *:13 *:* ÉCOUTER tcp 0 0 *:19 *:* ÉCOUTER tcp 0 0 *:37 *:* ÉCOUTER tcp 0 0 *:901 *:* ÉCOUTER tcp 0 0 *:1414 *:* ÉCOUTER tcp 0 0 *:81 *:* ÉCOUTER 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 ÉTABLI 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 ÉTABLI tcp 0 0 *:3001 *:* ÉCOUTER tcp 0 0 *:3002 *:* ÉCOUTER tcp 0 0 *:3003 *:* ÉCOUTER tcp 0 0 *:4000 *:* ÉCOUTER tcp 0 0 172.16.124.217:4000 172.16.124.78:1024 ÉTABLI tcp 0 0 172.16.124.217:4000 172.16.124.227:1025 ÉTABLI tcp 0 0 *:4001 *:* ÉCOUTER tcp 0 0 *:4002 *:* ÉCOUTER tcp 0 0 *:4003 *:* ÉCOUTER tcp 0 0 *:4004 *:* ÉCOUTER tcp 0 0 *:22 *:* ÉCOUTER tcp 0 0 *:4005 *:* ÉCOUTER tcp 0 0 *:4006 *:* ÉCOUTER tcp 0 0 172.16.124.217:4006 172.16.124.203:49231 ÉTABLI tcp 0 0 *:4007 *:* ÉCOUTER tcp 0 0 *:4008 *:* ÉCOUTER tcp 0 0 *:4009 *:* ÉCOUTER tcp 0 0 172.16.124.217:4008 172.16.124.203:49262 ÉTABLI tcp 0 0 *:4010 *:* ÉCOUTER tcp 0 0 *:4011 *:* ÉCOUTER tcp 0 0 *:4012 *:* ÉCOUTER tcp 0 0 *:4013 *:* ÉCOUTER tcp 0 0 *:4014 *:* ÉCOUTER tcp 0 0 *:4015 *:* ÉCOUTER tcp 0 0 *:80 *:* ÉCOUTER tcp 0 0 *:9182 *:* ÉCOUTER tcp 0 0 *:445 *:* ÉCOUTER tcp 0 0 *:139 *:* ÉCOUTER 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 ÉTABLI tcp 0 0 10.20.1.1:61707 10.20.1.3:48879 ÉTABLI 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 ÉTABLI |
Si vous comptez le nombre de lignes, vous en verrez plus de 42, car toutes les entrées affichées par netstat n'utilisent pas un clone de dispositif stcp. Par exemple, les connexions OSL et les connexions X25_cpc utilisées avec le NIO. Consultez le site socket_count.cm pour plus de détails.
Si un appel de socket est effectué sans connexion ou bind ou si le bind échoue, vous pouvez créer le problème inverse, la valeur de clone_count est plus grande que le nombre d'entrées indiqué par netstat.
as : match clone ; dump_dvt -name stcp.m17
clone_limit : 5120
clone_count : 4131
cloné_de : -23179
remote_clone_limit : 0
as :
|
Je n'inclus pas la sortie de netstat à nouveau, mais croyez-moi, elle n'a pas changé par rapport à l'exemple précédent.
Cette situation, un clone supplémentaire (4131 - 42) et apparemment non comptabilisé, du dispositif STCP a été créée par le fragment de code suivant. Le code appelle la fonction socket suivie de la fonction bind. Si le bind échoue, il se met en boucle. Beaucoup d'applications ajouteraient une minuterie 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 a déjà été 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;
}
}
|
Ce billet parle d'atteindre le clone_limit à cause 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 vraiment tous ces clones. Dans ce cas, si vous n'avez pas atteint la limite du système de 16 000, vous pouvez augmenter la limite. Vous devez mettre à jour le champ clone_limit du dispositif stcp dans le fichier devices.tin et recréer le devices.table. Si vous êtes sur une version 17.1 ou ultérieure, vous pouvez utiliser la commande update_device_info pour augmenter la limite pour le démarrage en cours et compter sur la mise à jour du fichier devices.table pour prendre en charge le prochain démarrage. Pour les versions antérieures à la 17.1, votre seule véritable option est de redémarrer. Vous devez fixer la limite à une valeur qui correspond à vos besoins actuels plus la croissance prévue ; vous ne devez pas vous contenter de relever la limite à 16 000. Même si vous n'avez pas un bogue d'application qui consomme des périphériques clones maintenant, il n'y a aucune garantie que vous n'en aurez pas un à l'avenir. Une application qui consomme tous les dispositifs de clonage disponibles consommera également beaucoup de mémoire de flux et l'épuisement de la mémoire de flux aura un effet négatif sur les connexions TCP existantes.