Sockets trouvés par lsof mais pas par netstat

19

J'ai une application qui manque de descripteurs de fichiers, apparemment en ouvrant des sockets, mais je ne peux pas savoir exactement ce que font ces sockets. Ceux-ci apparaissent dans la sortie lsof comme

java    9689 appuser 1010u  sock       0,5          263746675 can't identify protocol
java    9689 appuser 1011u  sock       0,5          263746676 can't identify protocol
java    9689 appuser 1012u  sock       0,5          263746677 can't identify protocol
java    9689 appuser 1014u  sock       0,5          263746678 can't identify protocol
java    9689 appuser 1015u  sock       0,5          263746679 can't identify protocol
java    9689 appuser 1016u  sock       0,5          263746681 can't identify protocol

et dans / proc / $ PID / fd as

lrwx------ 1 appuser appuser 64 Jun 23 11:49 990 -> socket:[263732085]
lrwx------ 1 appuser appuser 64 Jun 23 11:49 991 -> socket:[263732086]
lrwx------ 1 appuser appuser 64 Jun 23 11:49 992 -> socket:[263735307]
lrwx------ 1 appuser appuser 64 Jun 23 11:49 993 -> socket:[263732088]
lrwx------ 1 appuser appuser 64 Jun 23 11:49 995 -> socket:[263735308]
lrwx------ 1 appuser appuser 64 Jun 23 11:49 996 -> socket:[263735309]
lrwx------ 1 appuser appuser 64 Jun 23 11:49 997 -> socket:[263745434]
lrwx------ 1 appuser appuser 64 Jun 23 11:49 998 -> socket:[263745435]
lrwx------ 1 appuser appuser 64 Jun 23 11:49 999 -> socket:[263745436]

mais il n'y a pas de sortie similaire en netstat -a.

Que sont ces prises et comment savoir ce qu'elles font?

Edit : J'ai essayé de courir grep $SOCKET /proc/net, comme recommandé dans la FAQ lsof , où $ SOCKET est par exemple 263746679, mais cela n'a donné aucun résultat non plus.


En arrière-plan, l'application est un conteneur pour plusieurs tâches qui, entre autres, effectuent des appels réseau. Je dois distinguer celle qui devient folle, mais jusqu'à ce que je découvre avec qui ces prises communiquent, je suis coincé.

Robert Munteanu
la source
Nous sommes également confrontés récemment à ce problème avec l'une de nos applications Web .NET Core (serveur Ubuntu avec Kestrel), mais le périphérique enregistré est "0,9" avec le nom "protocole: TCP". Essayer de savoir exactement quels sont les appareils 0 et 9 s'est avéré difficile. Mais les symptômes semblent tous ressembler au même cas: ouvrir des prises sans les lier et les utiliser.
icelava

Réponses:

17

Cela peut se produire si vous créez un socket, mais ne vous connectez jamais () ou ne liez pas () avec lui. Le mieux est peut-être de mettre en forme (-fF) l'application, puis de faire un croisement avec la sortie de lsof pour déterminer les sockets à l'origine du problème. Comme méthode bonus de débogage: si vous encapsulez vos appels de socket avec des informations de débogage et les écrivez dans / dev / null, ils apparaîtront en strace sans vous donner des fichiers journaux hilarants.

BMDan
la source
Merci, cela semble intéressant. J'essaierai de savoir si tel est bien le cas avec notre candidature.
Robert Munteanu
1
Un peu sur la même ligne, car il s'agit de Java, il peut être très difficile d'utiliser strace; une meilleure méthode pourrait être de créer votre propre sous-classe de socket qui enregistre les informations avant de les transmettre au socket JDK parent (réel). strace ne peut voir que les appels Java sous-jacents au système d'exploitation et ne peut pas voir à l'intérieur de vos threads ce qui fait réellement ces appels de socket, pour que tout cela ressemble à une grosse boule de java.
troyengel
@troyengel: J'ai (re) découvert Byteman ( jboss.org/byteman ) un outil très soigné qui me permet d'injecter le bytecode nécessaire pour tracer ces appels.
Robert Munteanu
Réponse la plus utile, donc cela obtient la prime. Merci!
Robert Munteanu
2

En utilisant Python, j'ai rencontré le même problème sur les sockets SSL:

  • Lorsque j'utilise socket.close (), le socket reste dans l'état CLOSE_WAIT pendant une durée indéterminée
  • quand j'utilise socket.shutdown (), lsof dit "impossible d'identifier le protocole"

La solution était de déballer la couche SSL avant de fermer:

  • origsock = socket.unwrap ()
  • origsock.close ()

Cela ferme correctement les sockets dans mon application.

user48134
la source
1

La première chose que je ferais est d'augmenter la limite de descripteur de fichier:

~# vi /etc/sysctl.conf
fs.file-max = 331287

Ensuite, je m'assurerais que votre système est à jour, cela inclut toutes les bibliothèques et tous les serveurs. Il est possible que votre serveur d'applications Java soit obsolète (si vous en utilisez un). Il est également possible que votre serveur d'applications soit mal configuré, vous devriez regarder votre fichier de configuration et baisser votre connectionTimeoutet / ou votre maxKeepAliveRequests(je ne sais pas quel serveur d'applications vous utilisez ou si vous en utilisez un du tout ...).

Je ne suis pas sûr de ce que fait cette application, mais si vous ne pensez pas qu'elle nécessite des dizaines de milliers de sockets, il s'agit presque certainement d'une "fuite de descripteur de fichier" dans votre application Java. Vous devrez peut-être envoyer un rapport de bogue au fournisseur. Dans ce rapport de bogue, vous devez inclure des informations sur la façon de recréer le problème.

Voici quelques façons de déboguer le problème.

Wireshark (ou twireshark pour le cli) est le meilleur outil pour voir comment ces sockets sont utilisées. Wireshark vous donnera une ventilation du type de trafic jeté sur le câble. Il est probable que les premières connexions réussissent, puis il atteindra la limite de descripteur de fichier. Une fois que la limite de descripteur de fichier est atteinte, Wireshark ne va rien reprendre (et plus net est netstat d'ailleurs), mais cela aidera à réduire le problème. Il peut y avoir des cas où beaucoup de SYN sortants sont envoyés, mais aucun SYN / ACK n'est reçu, donc beaucoup de connexions TCP sont simplement bloquées dans l'état SYN_WAIT.

Si vous avez accès au code source et que vous connaissez le type de sockets en cours de création (comme utiliser strace ou simplement rechercher le code), vous pouvez ouvrir le projet dans Eclipse (ou un autre IDE) et définir un point d'arrêt à la fonction qui crée ces sockets. Lorsque le point d'arrêt est atteint, vous pouvez regarder la trace de la pile. Cette fuite de descripteur de fichier peut être une simple boucle infinie ou la valeur du délai d'expiration du socket est trop grande. Une autre possibilité est que l'application java ne socket.close()nettoie pas les connexions. Faire une fermeture se fait généralement dans un finelybloc de try/catch(Oui, un socket doit toujours avoir un try / catch en Java ou il ne se construira pas :). À la fin de la journée, il est probable que l'application Java ne gère pas correctement ses IOExceptions.

Tour
la source
Merci d'avoir répondu. Je suis en train de développer cette application - la partie conteneur - plutôt que de simplement la gérer, et je n'ai pas pu trouver de problèmes liés à la fermeture des sockets. Mais l'indication Wirehark / Twireshark est bonne, je vais l'utiliser.
Robert Munteanu
@Robert Munteanu Si vous construisez cette application, c'est une question pour stackoverflow. Néanmoins, vous ouvrez trop de prises.
Tour
Rook: J'ai renoncé à trouver cela au niveau du code et j'ai essayé de le retrouver en tant qu'administrateur système. C'est pourquoi j'ai posté sur SF. Et oui, je sais que trop de sockets sont ouvertes. Mais il n'y a aucun indice pour savoir où ...
Robert Munteanu
@Robert Munteanu Vous devez définir des points d'arrêt lors de la création du socket et regarder la trace de la pile et la mémoire à ce point. Je soupçonne que vous tombez dans une boucle infinie. Être capable de regarder n'importe quelle variable et étape bien que votre code soit la meilleure approche pour des problèmes complexes comme celui-ci.
Rook
Malheureusement, cela se produit apparemment au hasard sur l'un des 20 serveurs - pas toujours les mêmes -, uniquement dans les environnements de production, et peut-être deux fois par semaine. Sinon, il aurait été assez simple de les toucher. J'utilise actuellement Byteman ( jboss.org/byteman ) pour suivre les appels de création / liaison / connexion / fermeture de socket. Espérons que quelque chose en sortira.
Robert Munteanu