Socket akzeptieren - "Zu viele geöffnete Dateien"


72

Ich arbeite an einem Schulprojekt, in dem ich einen Multithread-Server schreiben musste, und jetzt vergleiche ich ihn mit Apache, indem ich einige Tests dagegen durchführe. Ich verwende Autobobench, um dies zu unterstützen, aber nachdem ich einige Tests durchgeführt habe oder wenn ich eine zu hohe Rate (ca. 600+) für das Herstellen der Verbindungen angegeben habe, wird der Fehler "Zu viele offene Dateien" angezeigt.

Nachdem ich mit der Bearbeitung der Anfrage fertig bin, mache ich immer eine close()an der Steckdose. Ich habe versucht, die shutdown()Funktion ebenfalls zu verwenden, aber nichts scheint zu helfen. Wie kann man das umgehen?

Antworten:


72

Es gibt mehrere Stellen, an denen Linux die Anzahl der Dateideskriptoren, die Sie öffnen dürfen, begrenzen kann.

Sie können Folgendes überprüfen:

Dadurch erhalten Sie die systemweiten Grenzen der Dateideskriptoren.

Auf der Shell-Ebene wird Ihnen dies Ihr persönliches Limit mitteilen:

Dies kann in /etc/security/limits.conf geändert werden - es ist der Nofile-Parameter.

Wenn Sie Ihre Sockets jedoch richtig schließen, sollten Sie dies nur erhalten, wenn Sie viele gleichzeitige Verbindungen öffnen. Es hört sich so an, als würde etwas verhindern, dass Ihre Steckdosen ordnungsgemäß geschlossen werden. Ich würde überprüfen, ob sie richtig behandelt werden.


Benutzername hard nofile 20000
linjunhalida

36

Ich hatte ein ähnliches Problem. Schnelle Lösung ist:

Die Erklärung lautet wie folgt: Jede Serververbindung ist ein Dateideskriptor. In CentOS, Redhat und Fedora, wahrscheinlich auch in anderen, liegt das Benutzerlimit für Dateien bei 1024 - keine Ahnung warum. Es kann leicht gesehen werden, wenn Sie Folgendes eingeben: ulimit -n

Beachten Sie, dass dies nicht viel mit System-Max-Dateien zu tun hat (/ proc / sys / fs / file-max).

In meinem Fall war es ein Problem mit Redis, also habe ich:

In Ihrem Fall müssen Sie anstelle von Redis Ihren Server starten.


6
Und die Antwort auf einen Speicherverlust lautet ... mehr Speicher kaufen? Nein, beheben Sie das Dateileck.
Rafael Baptista

5
Scheint, als ob Sie das Problem nicht verstehen (oder den Kommentar unter die falsche Antwort stellen?). Es hat mit dem Dateideskriptor-Limit zu tun und nichts mit Speicher oder Speicherverlust.
Nick

1
Das Dateilimit beträgt 1024, da Sie sonst auf ein grundlegendes Problem mit stoßenselect() .
flauschig

2
@RafaelBaptista In einigen Fällen wird tatsächlich eine hohe Anzahl gleichzeitiger Verbindungen benötigt, beispielsweise bei einem Hochleistungs-Chat-Server. Hierbei muss es nicht um undichte FDs gehen.
Antwan van Houdt

@ RafaelBaptista: Wenn Sie einen Server haben, der mehr als 512 parallere Verbindungen verarbeiten kann, benötigen Sie VIEL MEHR geöffnete Dateien. Moderne Server können mehrere Millionen parallele Verbindungen verarbeiten, sodass ein Limit von nur 1024 keinen Sinn ergibt. Dies ist möglicherweise in Ordnung für die Standardbegrenzung für Gelegenheitsbenutzer, jedoch nicht für Serversoftware, die parallele Clientverbindungen verarbeitet.
Mikko Rantalainen

17

TCP verfügt über eine Funktion namens "TIME_WAIT", die sicherstellt, dass Verbindungen sauber geschlossen werden. Es ist erforderlich, dass ein Ende der Verbindung nach dem Schließen des Sockets noch eine Weile lauscht.

In einem Hochleistungsserver ist es wichtig, dass die Clients in TIME_WAIT gehen, nicht der Server. Clients können es sich leisten, einen Port offen zu haben, während einem ausgelasteten Server schnell die Ports ausgehen oder zu viele offene FDs vorhanden sind.

Um dies zu erreichen, sollte der Server die Verbindung niemals zuerst schließen - er sollte immer darauf warten, dass der Client sie schließt.


2
Nein. TCP TIME_WAIT hält Sockets auf Betriebssystemebene offen und veranlasst den Server schließlich, eingehende Verbindungen abzulehnen. Wenn Sie das Dateihandle schließen, wird es geschlossen. stackoverflow.com/questions/1803566/…
Rafael Baptista

Es ist wahr, dass das Dateihandle sofort geschlossen wird und ich falsch geschrieben habe. Mein Hauptpunkt bleibt jedoch bestehen, denn obwohl der FD freigegeben ist, bleibt der TCP-Port während TIME_WAIT zugewiesen, und einem ausgelasteten Server können die TCP-Ports ausgehen oder es wird zu viel Kernelspeicher ausgegeben, um sie zu verfolgen.
Ed4

12

Verwenden Sie lsof -u `whoami` | wc -ldiese Option, um herauszufinden, wie viele offene Dateien der Benutzer hat


10

Dies bedeutet, dass die maximale Anzahl gleichzeitig geöffneter Dateien.

Gelöst:

Am Ende der Datei /etc/security/limits.confmüssen Sie die folgenden Zeilen hinzufügen:

In der aktuellen Konsole von root (sudo funktioniert nicht) zu tun:

Dies ist zwar optional, wenn der Server neu gestartet werden kann.

Im /etc/nginx/nginx.conf Datei, um den neuen Wert zu registrieren, der worker_connectionsgleich dem Wert 16384dividiert ist worker_processes.

Wenn dies nicht der Fall ist ulimit -n 16384, muss ein Neustart durchgeführt werden, damit das Problem behoben wird.

PS:

Wenn nach der Reparatur in den Protokollen sichtbar ist error accept() failed (24: Too many open files):

In der Nginx-Konfiguration Propevia (zum Beispiel):


6

Ich hatte auch dieses Problem. Sie haben ein Dateihandle-Leck. Sie können dies debuggen, indem Sie eine Liste aller geöffneten Dateihandles (auf POSIX-Systemen) ausdrucken:

Wenn Sie alle geöffneten Dateien ausgeben, können Sie schnell herausfinden, wo sich das Leck Ihres Dateihandles befindet.

Wenn Ihr Server Unterprozesse erzeugt. Wenn es sich beispielsweise um einen Server im Fork-Stil handelt oder wenn Sie andere Prozesse erzeugen (z. B. über CGI), müssen Sie sicherstellen, dass Ihre Dateihandles mit "cloexec" erstellt werden - sowohl für echte Dateien als auch für Sockets.

Ohne cloexec werden jedes Mal, wenn Sie gabeln oder spawnen, alle geöffneten Dateihandles im untergeordneten Prozess geklont.

Es ist auch sehr einfach, Netzwerk-Sockets nicht zu schließen - z. B. sie einfach zu verlassen, wenn die Remote-Partei die Verbindung trennt. Dies wird Griffe wie verrückt auslaufen lassen.


4

Es kann einige Zeit dauern, bis eine geschlossene Steckdose wirklich freigegeben ist

lsof um geöffnete Dateien aufzulisten

cat /proc/sys/fs/file-max um zu sehen, ob es ein Systemlimit gibt


2

Nur eine weitere Information über CentOS. In diesem Fall, wenn Sie "systemctl" zum Starten des Prozesses verwenden. Sie müssen die Systemdatei ändern ==> /usr/lib/systemd/system/processName.service. Hatte diese Zeile in der Datei:

Und laden Sie einfach Ihre Systemkonf neu:


1

Wenn Ihr Programm mehr offene Deskriptoren als die offenen Dateien ulimit hat (ulimit -a listet dies auf), weigert sich der Kernel, weitere Dateideskriptoren zu öffnen. Stellen Sie sicher, dass Sie keine Dateideskriptorlecks haben - indem Sie sie beispielsweise eine Weile ausführen, dann anhalten und prüfen, ob im Leerlauf noch zusätzliche FDS geöffnet sind - und wenn dies immer noch ein Problem ist, ändern Sie das Nofile-Ulimit für Ihr Benutzer in /etc/security/limits.conf


1

Ich hatte das gleiche Problem und habe mir nicht die Mühe gemacht, die Rückgabewerte der Aufrufe von close () zu überprüfen. Als ich anfing, den Rückgabewert zu überprüfen, verschwand das Problem auf mysteriöse Weise.

Ich kann nur einen Optimierungsfehler des Compilers annehmen (in meinem Fall gcc), gehe davon aus, dass close () -Aufrufe keine Nebenwirkungen haben und weggelassen werden können, wenn ihre Rückgabewerte nicht verwendet werden.


3
Es tut mir leid, dass das überhaupt nicht plausibel ist. Wenn eine sehr geringfügige Änderung in Ihrem Code dazu führte, dass der Fehler "verschwand", haben Sie höchstwahrscheinlich einen schwerwiegenden Fehler in Ihrem Code, den die Änderung verbarg. Verwenden Sie valgrindoder andere solche Tools, um es aufzuspüren. Ein Compiler, der einen closeAufruf optimiert , wäre katastrophal.
Mat

Genau. Es ist jedoch wichtig, den Rückgabewert eines Systemaufrufs zu überprüfen, da dies in EGAINvielen Fällen der Fall sein kann. Wenn Sie dies ignorieren, sind alle Wetten ungültig.
Mikko Rantalainen

0

Zeigen Sie unter MacOS die Grenzen an:

Ergebnis wie: maxfiles 256 1000

Wenn die Zahlen (Soft Limit & Hard Limit) zu niedrig sind, müssen Sie oben einstellen:


0

Zum späteren Nachschlagen stieß ich auf ein ähnliches Problem; Ich habe zu viele Dateideskriptoren (FDs) erstellt, indem ich zu viele Dateien und Sockets erstellt habe (unter Unix-Betriebssystemen ist alles ein FD). Meine Lösung bestand darin, die FDs zur Laufzeit mit zu erhöhen setrlimit().

Zuerst habe ich die FD-Grenzwerte mit dem folgenden Code erhalten:

// This goes somewhere in your code
struct rlimit rlim;

if (getrlimit(RLIMIT_NOFILE, &rlim) == 0) {
    std::cout << "Soft limit: " << rlim.rlim_cur << std::endl;
    std::cout << "Hard limit: " << rlim.rlim_max << std::endl;
} else {
    std::cout << "Unable to get file descriptor limits" << std::endl;
}

Nach dem Rennen getrlimit() konnte ich bestätigen, dass auf meinem System das Soft-Limit 256 FDs und das Hard-Limit unendlich FDs beträgt (dies hängt von Ihrer Distribution und Ihren Spezifikationen ab). Da ich zwischen Dateien und Sockets> 300 FDs erstellt habe, stürzte mein Code ab.

In meinem Fall konnte ich die Anzahl der FDs nicht verringern, daher habe ich beschlossen, stattdessen das FD-Softlimit mit diesem Code zu erhöhen:

// This goes somewhere in your code
struct rlimit rlim;

rlim.rlim_cur = NEW_SOFT_LIMIT;
rlim.rlim_max = NEW_HARD_LIMIT;

if (setrlimit(RLIMIT_NOFILE, &rlim) == -1) {
    std::cout << "Unable to set file descriptor limits" << std::endl;
}

Beachten Sie, dass Sie mit diesem Code auch die Anzahl der verwendeten FDs und die Quelle dieser FDs abrufen können .

Sie können auch weitere Informationen über finden gettrlimit()und setrlimit() hier und hier .


0

Ähnliches Problem unter Ubuntu 18 auf vsphere. Die Ursache - Die Konfigurationsdatei nginx.conf enthält zu viele Protokolldateien und Sockets. Sockets werden unter Linux als Dateien behandelt. Beim Neustart oder Neustart von nginx -s reload oder sudo service nginx wurde der Fehler Zu viele geöffnete Dateien in error.log angezeigt.

NGINX-Worker-Prozesse wurden vom NGINX-Benutzer gestartet. Ulimit (weich und hart) für Nginx-Benutzer war 65536. Die ulimit- und Einstellungslimits.conf funktionierten nicht.

Die rlimit-Einstellung in nginx.conf hat auch nicht geholfen: worker_rlimit_nofile 65536;

Die Lösung, die funktionierte, war:

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.