J'ai un problème étrange avec un serveur acceptant les connexions TCP. Même s'il y a normalement des processus en attente, à un certain volume de connexions il se bloque.Pourquoi mon script de serveur Perl TCP se bloque-t-il avec de nombreuses connexions TCP?
Version longue:
Le serveur est écrit en Perl et se lie à une prise $srv
avec le drapeau de la réutilisation et écouter == 5. Ensuite, il forke en 10 processus avec une boucle de $clt=$srv->accept(); do_processing($clt); $clt->shutdown(2);
Le client écrit en C est aussi très simple - il envoie des lignes, puis reçoit toutes les lignes disponibles et fait shutdown(sockfd, 2);
Il n'y a rien d'asynchrone qui se passe et à la fin les files d'attente d'envoi et de réception sont vides (comme indiqué par netstat
).
Les connexions ne durent que ~ 20ms. Tous les clients se comportent de la même manière, ont la même implémentation, etc. Supposons maintenant que j'accepte les connexions X
du client 1 et une autre X
du client 2. Les processus indiquent toujours qu'ils sont inactifs tout le temps. Si j'ajoute un autre X
connexions du client 3, soudainement les processus de serveur commencent à se suspendre juste après avoir accepté. Le premier blocage qu'ils font après accept();
est while (<$clt>) ...
- mais ils n'obtiennent aucune donnée (dès le premier essai). Soudain, tous les 10 processus sont dans cet état et n'arrêtent pas d'attendre. Sur strace
, les processus serveur semblent se bloquer sur read()
, ce qui est logique.
Il y a des charges de connexions dans l'état TIME_WAIT
appartenant à ce serveur (~ 100 lorsque le problème commence à se manifester), mais cela pourrait être un faux-fuyant.
Que pourrait-il se passer ici? Après un peu plus d'analyse: Il s'est avéré que le client était fautif, ne fermant pas correctement les connexions précédentes avant d'essayer le suivant. Les serveurs au début de la liste d'équilibrage de charge étaient des connexions périmées.
Avez-vous désactivé la mise en mémoire tampon sur toutes vos sockets? Vous devrez peut-être poster d'autres exemples de code. –
Vous ne savez pas ce que je peux vous donner ici en code - c'est vraiment simple. Le serveur fonctionne sur des lignes, donc les lectures sont mises en mémoire tampon et traitées avec '<...>' - sauf si vous voulez dire quelque chose d'autre ici? Le code client C fait un standard 'connect (...);' et write (sockfd, request, ...); '- j'essaierai de désactiver la mise en mémoire tampon ici et de rendre compte. – viraptor
@Eric Strom: Je suis confus maintenant - que vouliez-vous dire en désactivant la mise en mémoire tampon? J'utilise un simple 'write (...)' côté client - il y a bien sûr du nagle, mais cela garantit le transfert dans les 0.2s suivants (plus ou moins). Alors, quel genre de tampon aviez-vous en tête? – viraptor