Contagem máxima de threads no Linux

8

meu servidor está sendo executado com o Amazon Ec2 linux. Eu tenho um servidor mongodb dentro. O servidor mongodb está sendo executado com muita carga e, infelizmente, tive um problema com ele: /

Como se sabe, o mongodb cria um novo encadeamento para cada conexão do cliente, e isso funcionou bem antes. Não sei por que, mas o MongoDB não pode criar mais de 975 conexões no host como um usuário não privilegiado (ele é executado sob um usuário mongod). Mas quando estou executando-o como usuário root, ele pode lidar com até 20.000 conexões (limite interno do mongodb). Porém, investigações adicionais mostram que esse problema não é o servidor MongoDB, mas um linux em si.

Encontrei um programa simples, que verifica o número máximo de conexões:

/* 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);
}

E a suturação é repetida novamente, como usuário root, posso criar cerca de 32k threads, como usuário não privilegiado (mongod ou ec2-user) por volta de 1000.

Este é um ulimit para usuário root:

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

Este é um ulimit para o usuário mongod:

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

Máximo de threads do kernel:

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

O SELinux está desativado. Não sei como resolver esse problema estranho ... Possivelmente alguém sabe?

Sergei Lomakov
fonte

Respostas:

12

Seu problema é o max user processeslimite.

Na getrlimit(2)página do manual:

RLIMIT_NPROC O número máximo de processos (ou, mais precisamente no Linux, threads) que podem ser criados para o ID do usuário real do processo de chamada. Ao encontrar esse limite, fork(2)falha com o erro EAGAIN.

Mesmo para pthread_create(3):

EAGAINRecursos insuficientes para criar outro encadeamento ou um limite imposto pelo sistema ao número de encadeamentos foi encontrado. O último caso pode ocorrer de duas maneiras: o RLIMIT_NPROClimite de recurso programável (definido via setrlimit(2)), que limita o número de processos para um ID de usuário real, foi atingido; ou o limite de todo o sistema do kernel no número de threads /proc/sys/kernel/threads-max, foi atingido.

Aumente esse limite para o usuário e ele poderá criar mais threads, até atingir outros limites de recursos.
Ou exaustão de recursos - para pilha de 1Mb e threads de 20k, você precisará de muita RAM.
Veja também o NPTL limita o número máximo de threads em 65528? : /proc/sys/vm/max_map_countpode se tornar um problema em algum momento.

Ponto lateral: você deve usar em -pthreadvez de -lpthread. Veja gcc - significado do sinalizador -pthread ao compilar .

Esteira
fonte
0

Corremos esse problema quando problemas de conexão do cliente mongo (java) eram interrompidos (ao que parece pela rede da AWS). Com TCP_KEEPALIVE definido como 7200 (2 horas), as conexões nos conjuntos de conexões são construídas nessa janela de 2 horas e o mongod morre quando atinge 975 conexões.

A lista de verificação da produção do mongo sugere uma vida útil muito menor (5 minutos); configuração que deve ajudá-lo a evitar também o limite de conexão.

Brett
fonte