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?
Ich hatte ein ähnliches Problem. Schnelle Lösung ist:
ulimit -n 4096
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:
ulimit -n 4096 redis-server -c xxxx
In Ihrem Fall müssen Sie anstelle von Redis Ihren Server starten.
quelle
select()
.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.
quelle
Verwenden Sie
lsof -u `whoami` | wc -l
diese Option, um herauszufinden, wie viele offene Dateien der Benutzer hatquelle
Dies bedeutet, dass die maximale Anzahl gleichzeitig geöffneter Dateien.
Gelöst:
Am Ende der Datei
/etc/security/limits.conf
müssen Sie die folgenden Zeilen hinzufügen:* soft nofile 16384 * hard nofile 16384
In der aktuellen Konsole von root (sudo funktioniert nicht) zu tun:
ulimit -n 16384
Dies ist zwar optional, wenn der Server neu gestartet werden kann.
Im
/etc/nginx/nginx.conf
Datei, um den neuen Wert zu registrieren, derworker_connections
gleich dem Wert16384
dividiert istworker_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):
worker_processes 2; worker_rlimit_nofile 16384; events { worker_connections 8192; }
quelle
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:
void showFDInfo() { s32 numHandles = getdtablesize(); for ( s32 i = 0; i < numHandles; i++ ) { s32 fd_flags = fcntl( i, F_GETFD ); if ( fd_flags == -1 ) continue; showFDInfo( i ); } } void showFDInfo( s32 fd ) { char buf[256]; s32 fd_flags = fcntl( fd, F_GETFD ); if ( fd_flags == -1 ) return; s32 fl_flags = fcntl( fd, F_GETFL ); if ( fl_flags == -1 ) return; char path[256]; sprintf( path, "/proc/self/fd/%d", fd ); memset( &buf[0], 0, 256 ); ssize_t s = readlink( path, &buf[0], 256 ); if ( s == -1 ) { cerr << " (" << path << "): " << "not available"; return; } cerr << fd << " (" << buf << "): "; if ( fd_flags & FD_CLOEXEC ) cerr << "cloexec "; // file status if ( fl_flags & O_APPEND ) cerr << "append "; if ( fl_flags & O_NONBLOCK ) cerr << "nonblock "; // acc mode if ( fl_flags & O_RDONLY ) cerr << "read-only "; if ( fl_flags & O_RDWR ) cerr << "read-write "; if ( fl_flags & O_WRONLY ) cerr << "write-only "; if ( fl_flags & O_DSYNC ) cerr << "dsync "; if ( fl_flags & O_RSYNC ) cerr << "rsync "; if ( fl_flags & O_SYNC ) cerr << "sync "; struct flock fl; fl.l_type = F_WRLCK; fl.l_whence = 0; fl.l_start = 0; fl.l_len = 0; fcntl( fd, F_GETLK, &fl ); if ( fl.l_type != F_UNLCK ) { if ( fl.l_type == F_WRLCK ) cerr << "write-locked"; else cerr << "read-locked"; cerr << "(pid:" << fl.l_pid << ") "; } }
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.
quelle
Es kann einige Zeit dauern, bis eine geschlossene Steckdose wirklich freigegeben ist
lsof
um geöffnete Dateien aufzulistencat /proc/sys/fs/file-max
um zu sehen, ob es ein Systemlimit gibtquelle
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:
LimitNOFILE=50000
Und laden Sie einfach Ihre Systemkonf neu:
quelle
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
quelle
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.
quelle
valgrind
oder andere solche Tools, um es aufzuspüren. Ein Compiler, der einenclose
Aufruf optimiert , wäre katastrophal.EGAIN
vielen Fällen der Fall sein kann. Wenn Sie dies ignorieren, sind alle Wetten ungültig.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:
sudo launchctl limit maxfiles 65536 200000
quelle
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()
undsetrlimit()
hier und hier .quelle
Ä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:
$ mkdir -p /etc/systemd/system/nginx.service.d $ nano /etc/systemd/system/nginx.service.d/nginx.conf [Service] LimitNOFILE=30000 $ systemctl daemon-reload $ systemctl restart nginx.service
quelle