2009-05-19 13 views
43

Ich arbeite an einem Schulprojekt, wo ich einen Multi-Thread-Server schreiben musste, und jetzt vergleiche ich es mit Apache, indem ich einige Tests dagegen durchführe. Ich benutze Autobank, um damit zu helfen, aber nachdem ich ein paar Tests ausgeführt habe, oder wenn ich es zu hoch Rate (um 600+) geben, um die Verbindungen zu machen, bekomme ich einen "Too many open files" Fehler.Socket accept - "Zu viele offene Dateien"

Nachdem ich mit dem Umgang mit der Anfrage fertig bin, mache ich immer eine close() auf dem Sockel. Ich habe versucht, die shutdown() Funktion auch zu verwenden, aber nichts scheint zu helfen. Irgendwie in der Nähe?

Antwort

47

Es gibt mehrere Orte, an denen Linux Sie können Beschränkungen für die Anzahl der Dateideskriptoren haben, die Sie öffnen dürfen.

Sie können folgende überprüfen:

cat /proc/sys/fs/file-max 

Dass Sie weiten Grenzen von Filedeskriptoren das System geben.

Auf der Shell-Ebene, wird diese Sie Ihre persönliche Grenze sagen:

ulimit -n 

Diese in /etc/security/limits.conf geändert werden kann - es ist die nofile param.

Wenn Sie jedoch Ihre Sockets korrekt schließen, sollten Sie dies nicht erhalten, es sei denn, Sie öffnen eine Vielzahl von simultanen Verbindungen. Es hört sich so an, als würde etwas verhindern, dass deine Buchsen richtig geschlossen werden. Ich würde bestätigen, dass sie richtig behandelt werden.

+0

Ich bearbeite /etc/security/limits.conf mit: – linjunhalida

+0

Benutzername HardNofile 20000 – linjunhalida

4

es ein wenig Zeit in Anspruch nehmen kann, bevor eine geschlossene Buchse wirklich bis befreit

lsof zur Liste geöffnete Dateien

cat /proc/sys/fs/file-max, um zu sehen, ob es eine Systemgrenze ist

1

Wenn Ihr Programm mehr offene Deskriptoren hat als die geöffneten Dateien ulimit (ulimit -a listet dies auf), wird der Kernel weigern, weitere Dateideskriptoren zu öffnen. Stellen Sie sicher, dass Sie keine Dateideskriptoren-Lecks haben, zum Beispiel indem Sie sie eine Weile ausführen und dann anhalten und sehen, ob noch weitere fds geöffnet sind, und wenn es immer noch ein Problem ist, ändern Sie die Nofile ulimit für Ihre Benutzer in /etc/security/limits.conf

12

TCP verfügt über eine Funktion namens "TIME_WAIT", die sicherstellt, dass die Verbindungen sauber geschlossen sind. Es erfordert ein Ende der Verbindung, um eine Weile zu warten, nachdem der Socket geschlossen wurde.

In einem Hochleistungsserver ist es wichtig, dass es sich bei den Clients um TIME_WAIT handelt, nicht um den Server. Clients können es sich leisten, einen Port geöffnet zu haben, während einem ausgelasteten Server die Ports schnell ausgehen können oder zu viele offene FDs haben.

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

+2

Nr. TCP TIME_WAIT wird Sockets offen auf der Betriebssystemebene halten und schließlich den Server eingehende Verbindungen ablehnen. Wenn Sie das Dateihandle schließen, wird es geschlossen. http://stackoverflow.com/questions/1803566/what-is-the-cost-of-many-time-wait-on-the-server-side –

+0

Es ist wahr, dass das Datei-Handle sofort schließt und ich mistpoke. Aber mein Hauptpunkt steht immer noch, denn obwohl der FD freigegeben ist, bleibt der TCP-Port während TIME_WAIT reserviert, und einem ausgelasteten Server können die TCP-Ports ausgehen oder zu viel Kernelspeicher ausgeben, um sie zu verfolgen. – Ed4

5

Verwenden lsof -u `whoami` | wc -l zu finden, wie viele offene Dateien der Benutzer

15

Ich hatte ähnliches Problem hat. Schnell Lösung ist:

ulimit -n 4096 

Erklärung dafür ist wie folgt - jeder Server-Verbindung ein Dateideskriptor ist.In CentOS, Redhat und Fedora, wahrscheinlich anderen, ist das Limit für die Dateibenutzer 1024 - keine Ahnung warum. Es kann leicht gesehen werden, wenn Sie Folgendes eingeben: ulimit -n

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

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

ulimit -n 4096 
redis-server -c xxxx 

in Ihrem Fall statt redis, müssen Sie Ihren Server starten.

+2

Und die Antwort auf ein Speicherleck ist ... mehr Speicher kaufen? No fix das Dateileck. –

+2

Scheint, du verstehst das Problem nicht (oder du stellst den Kommentar unter falsche Antwort?) Es hat mit Datei-Deskriptor Grenze zu tun, und nichts mit Speicher oder Speicherverlust zu tun. – Nick

+1

Das Dateilimit ist 1024, weil Sie sonst laufen in ein [grundlegendes Problem mit 'select()'] (http://beesbuzz.biz/blog/e/2013/10/10-the_problem_with_select_vs_poll.php) – fluffy

1

Ich hatte das gleiche Problem und ich war nicht daran interessiert, die Rückgabewerte der close() -Aufrufe 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 (gcc in meinem Fall) annehmen, geht davon aus, dass close() Aufrufe ohne Nebenwirkungen sind und können weggelassen werden, wenn ihre Rückgabewerte nicht verwendet werden.

+2

Es tut mir leid, dass ist überhaupt nicht plausibel. Wenn eine sehr geringfügige Änderung in Ihrem Code den Fehler "weggehen", Sie am meisten Wahrscheinlich haben Sie einen schwerwiegenden Fehler in Ihrem Code, den die Änderung verbarg. Verwenden Sie 'valgrind' oder andere solche Tools, um sie aufzuspüren. Ein Compiler, der einen 'close'-Aufruf optimiert, wäre katastrophal c. – Mat

5

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

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 << ") "; 
    } 
} 

Durch alle geöffneten Dateien Dumping aus Sie schnell wird herausfinden, wo Ihre Datei Handle-Leck ist.

Wenn Ihr Server Subprozesse hervorbringt. Z.B. Wenn es sich um einen Server im Fork-Stil handelt oder wenn Sie andere Prozesse generieren (z. B. über CGI), müssen Sie sicherstellen, dass Sie Ihre Datei-Handles mit "cloexec" erstellen - sowohl für echte Dateien als auch für Sockets.

Ohne Cloexec werden bei jedem Fork- oder Spawn-Aufruf alle geöffneten Dateizugriffsnummern im untergeordneten Prozess geklont.

Es ist auch sehr einfach zu versäumen, Netzwerk-Sockets zu schließen - z. Verlassen Sie sie einfach, wenn der Remote-Teilnehmer die Verbindung trennt. Dies wird Griffe wie verrückt auslaufen lassen.

4

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

Gelöst:

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

* soft nofile 16384 
* hard nofile 16384 

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

Obwohl dies optional ist, wenn es möglich ist, den Server neu zu starten.

In /etc/nginx/nginx.conf Datei Wert worker_processes den neuen Wert gleich worker_connections16384 divide zu registrieren.

Wenn nicht ulimit -n 16384, muss neu gestartet werden, dann wird das Problem zurücktreten.

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; 
} 
0

Nur eine weitere Informationen über CentOS . In diesem Fall, wenn Sie "systemctl" verwenden, um den Prozess zu starten. Sie müssen die Systemdatei ändern ==> /usr/lib/systemd/system/processName.service .Had diese Zeile in der Datei:

LimitNOFILE=50000 

Und Ihr System conf nachladen:

systemctl daemon-reload 
Verwandte Themen