Linux max Threads zählen

8

Mein Server wurde mit Amazon Ec2 Linux ausgeführt. Ich habe einen Mongodb-Server im Inneren. Der Mongodb-Server wurde stark ausgelastet, und leider bin ich auf ein Problem damit gestoßen: /

Wie bekannt, erstellt der Mongodb für jede Clientverbindung einen neuen Thread, und dies hat zuvor einwandfrei funktioniert. Ich weiß nicht warum, aber MongoDB kann nicht mehr als 975 Verbindungen auf dem Host als nicht privilegierter Benutzer erstellen (es läuft unter einem Mongod-Benutzer). Aber wenn ich es als Root-Benutzer ausführe, kann es bis zu 20000 Verbindungen verarbeiten (internes Mongodb-Limit). Weitere Untersuchungen zeigen jedoch, dass dieses Problem nicht der MongoDB-Server ist, sondern ein Linux selbst.

Ich habe ein einfaches Programm gefunden, das die maximale Anzahl von Verbindungen überprüft:

/* compile with:   gcc -lpthread -o thread-limit thread-limit.c */
/* originally from: http://www.volano.com/linuxnotes.html */

#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <pthread.h>
#include <string.h>

#define MAX_THREADS 100000
#define PTHREAD_STACK_MIN 1*1024*1024*1024
int i;

void run(void) {
  sleep(60 * 60);
}

int main(int argc, char *argv[]) {
  int rc = 0;
  pthread_t thread[MAX_THREADS];
  pthread_attr_t thread_attr;

  pthread_attr_init(&thread_attr);
  pthread_attr_setstacksize(&thread_attr, PTHREAD_STACK_MIN);

  printf("Creating threads ...\n");
  for (i = 0; i < MAX_THREADS && rc == 0; i++) {
    rc = pthread_create(&(thread[i]), &thread_attr, (void *) &run, NULL);
    if (rc == 0) {
      pthread_detach(thread[i]);
      if ((i + 1) % 100 == 0)
    printf("%i threads so far ...\n", i + 1);
    }
    else
    {
      printf("Failed with return code %i creating thread %i (%s).\n",
         rc, i + 1, strerror(rc));

      // can we allocate memory?
      char *block = NULL;
      block = malloc(65545);
      if(block == NULL)
        printf("Malloc failed too :( \n");
      else
        printf("Malloc worked, hmmm\n");
    }
  }
sleep(60*60); // ctrl+c to exit; makes it easier to see mem use
  exit(0);
}

Und die Sutuation wird noch einmal wiederholt, als Root-Benutzer kann ich ungefähr 32k Threads erstellen, als nicht privilegierter Benutzer (Mongod oder Ec2-Benutzer) ungefähr 1000.

Dies ist ein Ulimit für Root-Benutzer:

core file size          (blocks, -c) 0
data seg size           (kbytes, -d) unlimited
scheduling priority             (-e) 0
file size               (blocks, -f) unlimited
pending signals                 (-i) 59470
max locked memory       (kbytes, -l) 64
max memory size         (kbytes, -m) unlimited
open files                      (-n) 60000
pipe size            (512 bytes, -p) 8
POSIX message queues     (bytes, -q) 819200
real-time priority              (-r) 0
stack size              (kbytes, -s) 8192
cpu time               (seconds, -t) unlimited
max user processes              (-u) 1024
virtual memory          (kbytes, -v) unlimited
file locks                      (-x) unlimited

Dies ist ein Ulimit für Mongod-Benutzer:

core file size          (blocks, -c) 0
data seg size           (kbytes, -d) unlimited
scheduling priority             (-e) 0
file size               (blocks, -f) unlimited
pending signals                 (-i) 59470
max locked memory       (kbytes, -l) 64
max memory size         (kbytes, -m) unlimited
open files                      (-n) 60000
pipe size            (512 bytes, -p) 8
POSIX message queues     (bytes, -q) 819200
real-time priority              (-r) 0
stack size              (kbytes, -s) 1024
cpu time               (seconds, -t) unlimited
max user processes              (-u) 1024
virtual memory          (kbytes, -v) unlimited
file locks                      (-x) unlimited

Kernel max Threads:

bash-4.1$ cat /proc/sys/kernel/threads-max 
118940

SELinux ist deaktiviert. Sie wissen nicht, wie Sie dieses seltsame Problem lösen sollen ... Möglicherweise tut es jemand?

Sergei Lomakov
quelle

Antworten:

12

Ihr Problem ist die max user processesGrenze.

Von der getrlimit(2)Manpage:

RLIMIT_NPROC Die maximale Anzahl von Prozessen (oder genauer gesagt unter Linux Threads), die für die tatsächliche Benutzer-ID des aufrufenden Prozesses erstellt werden können. Wenn dieser Grenzwert erreicht wird, fork(2)schlägt der Fehler fehl EAGAIN.

Gleiches gilt für pthread_create(3):

EAGAINEs wurden nicht genügend Ressourcen zum Erstellen eines anderen Threads oder eine vom System auferlegte Begrenzung der Anzahl der Threads festgestellt. Der letztere Fall kann auf zwei Arten auftreten: Das RLIMIT_NPROCSoft-Ressourcen-Limit (festgelegt über setrlimit(2)), das die Anzahl der Prozesse für eine echte Benutzer-ID begrenzt, wurde erreicht. oder die systemweite Begrenzung der Anzahl der Threads durch den Kernel /proc/sys/kernel/threads-maxwurde erreicht.

Erhöhen Sie dieses Limit für Ihren Benutzer, und es sollte in der Lage sein, mehr Threads zu erstellen, bis andere Ressourcenlimits erreicht sind.
Oder einfache Ressourcenerschöpfung - für 1 MB Stack und 20.000 Threads benötigen Sie viel RAM.
Siehe auch NPTL-Kappen maximaler Gewinde bei 65528? : /proc/sys/vm/max_map_countkönnte irgendwann zu einem Problem werden.

Nebenpunkt: Sie sollten -pthreadanstelle von verwenden -lpthread. Siehe gcc - Bedeutung des Flags -pthread beim Kompilieren .

Matte
quelle
0

Wir sind auf dieses Problem gestoßen, als Verbindungsprobleme vom Mongo-Client (Java) unterbrochen wurden (anscheinend vom AWS-Netzwerk). Wenn TCP_KEEPALIVE auf 7200 (2 Stunden) eingestellt ist, werden die Verbindungen in Verbindungspools innerhalb dieses 2-Stunden-Fensters aufgebaut, und Mongod stirbt, wenn 975 Verbindungen erreicht werden.

Die Checkliste für die Mongo-Produktion schlägt Keepalives mit einer viel kürzeren Zeit (5 Minuten) vor. Einstellungen, mit denen Sie auch das Verbindungslimit umgehen können.

Brett
quelle