Sockets gefunden von lsof, aber nicht von netstat

19

Ich habe eine Anwendung, der die Dateideskriptoren ausgehen, anscheinend indem ich Sockets öffne, aber ich kann nicht genau herausfinden, was diese Sockets tun. Diese erscheinen in der Ausgabe als

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

und in / proc / $ PID / fd als

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]

aber es gibt keine ähnliche Ausgabe in netstat -a.

Was sind diese Steckdosen und wie kann ich herausfinden, was sie tun?

Bearbeiten : Ich habe versucht, ausgeführt grep $SOCKET /proc/net, wie in den lsof-FAQ empfohlen , wobei $ SOCKET beispielsweise 263746679 ist, aber das gab auch keine Ergebnisse.


Als Hintergrund ist die Anwendung ein Container für mehrere Aufgaben, die unter anderem Netzwerkaufrufe durchführen. Ich muss den heraussuchen, der wahnsinnig wird, aber bis ich herausfinde, mit wem diese Steckdosen kommunizieren, stecke ich fest.

Robert Munteanu
quelle
Wir haben dieses Problem kürzlich auch mit einer unserer .NET Core-Web-Apps (Ubuntu-Server mit Kestrel) zu kämpfen, aber das aufgezeichnete Gerät ist "0,9" mit dem Namen "protocol: TCP". Es hat sich als schwierig erwiesen, herauszufinden, welche Geräte 0 und 9 genau sind. Aber die Symptome sehen alle so aus, als würden Steckdosen geöffnet, ohne sie zu binden und zu benutzen.
Icelava

Antworten:

17

Dies kann auftreten, wenn Sie einen Socket erstellen, ihn jedoch niemals verbinden () oder binden (). Am besten ist es, die Anwendung zu stracen (-fF) und dann mit der Ausgabe von lsof zu verweisen, um zu bestimmen, welche Sockets das Problem verursachen. Als Bonusmethode für das Debuggen: Wenn Sie Ihre Socket-Aufrufe mit Debugging-Informationen versehen und an / dev / null ausschreiben, wird dies in Kürze angezeigt, ohne dass Sie unglaublich große Protokolldateien erhalten.

BMDan
quelle
Danke, das hört sich interessant an. Ich werde versuchen herauszufinden, ob dies bei unserer Bewerbung tatsächlich der Fall ist.
Robert Munteanu
1
Etwas in die gleiche Richtung, da dies Java ist, könnte es sehr schwierig sein, strace zu verwenden. Eine bessere Methode könnte darin bestehen, eine eigene Socket-Unterklasse zu erstellen, die Informationen protokolliert, bevor sie an den übergeordneten (echten) JDK-Socket übergeben werden. strace kann nur die zugrunde liegenden Java-Aufrufe des Betriebssystems sehen und nicht in Ihren Threads nachvollziehen, was diese Socket-Aufrufe tatsächlich verursacht.
Troyengel
@troyengel: Ich habe Byteman ( jboss.org/byteman ) (wieder) entdeckt, ein sehr übersichtliches Tool, mit dem ich den Bytecode einfügen kann, der zum Verfolgen dieser Aufrufe erforderlich ist.
Robert Munteanu
Nützlichste Antwort, damit das die Prämie bekommt. Vielen Dank!
Robert Munteanu
2

Mit Python habe ich das gleiche Problem bei SSL-Sockets festgestellt:

  • Wenn ich socket.close () verwende, bleibt der Socket für unbestimmte Zeit im Zustand CLOSE_WAIT
  • wenn ich socket.shutdown () benutze, sagt lsof "kann das Protokoll nicht identifizieren"

Die Lösung bestand darin, die SSL-Ebene vor dem Schließen zu entpacken:

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

Dadurch werden die Sockets in meiner App ordnungsgemäß geschlossen.

user48134
quelle
1

Das erste, was ich tun würde, ist zu erhöhen, wenn Ihre Dateideskriptor-Grenze:

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

Als nächstes würde ich sicherstellen, dass Ihr System auf dem neuesten Stand ist, dies schließt alle Bibliotheken und Server ein. Möglicherweise ist Ihr Java-Anwendungsserver veraltet (falls Sie einen verwenden). Es ist auch möglich, dass Ihr Anwendungsserver falsch konfiguriert ist. Sehen Sie sich Ihre Konfigurationsdatei an und senken Sie Ihre connectionTimeoutund / oder Ihre maxKeepAliveRequests(ich bin nicht sicher, welchen Anwendungsserver Sie verwenden oder ob Sie überhaupt einen verwenden ...).

Ich bin mir nicht sicher, was diese Anwendung bewirkt, aber wenn Sie nicht glauben, dass Zehntausende von Sockets erforderlich sind, ist dies mit ziemlicher Sicherheit ein "Dateideskriptorleck" in Ihrer Java-Anwendung. Möglicherweise müssen Sie einen Fehlerbericht an den Anbieter senden. In diesem Fehlerbericht sollten Sie Informationen zum erneuten Erstellen des Problems enthalten.

Hier finden Sie einige Möglichkeiten zum Debuggen des Problems.

Wireshark (oder Twireshark für das CLI) ist das beste Werkzeug, um zu sehen, wie diese Sockel verwendet werden. Wireshark gibt Ihnen eine Aufschlüsselung der Art des Verkehrs, der über das Kabel geworfen wird. Es ist wahrscheinlich, dass die ersten Verbindungen erfolgreich sind und dann das Dateideskriptorlimit erreicht wird. Sobald das Dateideskriptorlimit erreicht ist, wird Wireshark nichts mehr bemerken (und in diesem Fall ist es netter als netstat), aber dies wird helfen, das Problem einzugrenzen. Es kann vorkommen, dass viele ausgehende SYNs gesendet werden, jedoch keine SYN / ACKs empfangen werden, sodass viele TCP-Verbindungen nur im SYN_WAIT-Status hängen bleiben.

Wenn Sie Zugriff auf den Quellcode haben und wissen, welche Sockets erstellt werden (z. B. mit strace oder nur durch Durchsuchen des Codes), können Sie das Projekt in Eclipse (oder einer anderen IDE) öffnen und bei der Funktion that einen Haltepunkt setzen schafft diese Sockets. Wenn der Haltepunkt erreicht wird, können Sie den Stack-Trace anzeigen. Bei diesem Dateideskriptorleck handelt es sich möglicherweise um eine einfache Endlosschleife, oder der Socket-Timeout-Wert ist zu groß. Eine andere Möglichkeit besteht darin, dass die Java-App socket.close()die Verbindungen nicht bereinigt. Das Schließen wird normalerweise im finelyBlock a ausgeführt try/catch(Ja, ein Socket muss in Java immer einen try / catch-Befehl haben, sonst wird er nicht erstellt :). Letztendlich ist es wahrscheinlich, dass die Java-App ihre IOException nicht richtig verarbeitet.

Turm
quelle
Danke für die Antwort. Ich entwickle diese Anwendung - den Containerteil -, anstatt sie nur zu verwalten, und konnte keine Probleme feststellen, die damit zusammenhängen, dass Sockets nicht geschlossen wurden. Aber der Wireshark / Twireshark-Hinweis ist gut, das werde ich verwenden.
Robert Munteanu
@Robert Munteanu Wenn Sie diese App erstellen, ist dies eine Frage für den Stackoverflow. Trotzdem öffnen Sie zu viele Steckdosen.
Rook
Rook: Ich habe es aufgegeben, dies in Bezug auf den Code herauszufinden, und habe versucht, es als Sysadmin aufzuspüren. Deshalb habe ich auf SF gepostet. Und ja, ich weiß irgendwie, dass zu viele Steckdosen offen sind. Aber es gibt keine Hinweise, wo ...
Robert Munteanu
@Robert Munteanu Sie müssen bei der Socket-Erstellung Haltepunkte setzen und den Stack-Trace und den Speicher an diesem Punkt überprüfen. Ich vermute, Sie geraten in eine Endlosschleife. In der Lage zu sein, jede Variable zu betrachten und einen Schritt durch den Code zu tun, ist der beste Ansatz für komplexe Probleme wie dieses.
Rook
Leider geschieht dies scheinbar zufällig auf einem von 20 Servern - nicht immer gleich -, nur in Produktionsumgebungen und vielleicht zweimal pro Woche. Andernfalls wäre es ziemlich einfach gewesen, mit den Fingern zu spielen. Ich verwende derzeit Byteman ( jboss.org/byteman ), um das Erstellen / Binden / Verbinden / Schließen von Sockets zu verfolgen. Hoffentlich kommt etwas dabei heraus.
Robert Munteanu