Contagem máxima de encadeamentos do Linux

8

meu servidor foi executado com o Amazon Ec2 linux. Eu tenho um servidor mongodb dentro. O servidor mongodb foi executado sob carga pesada e, infelizmente, tive um problema com ele: /

Como é conhecido, o mongodb cria um novo thread para cada conexão do cliente, e isso funcionou bem antes. Eu não sei porque, 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 eu estou executando como um usuário root, ele pode manipular até 20000 conexões (limite interno do mongodb). Mas, investigações posteriores mostram que o problema não é o servidor MongoDB, mas um linux em si.

Eu 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 sutuação é repetida novamente, como usuário root eu 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

Encadeamentos máximos 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 faz?

    
por Sergei Lomakov 09.09.2012 / 07:16

2 respostas

12

Seu problema é o max user processes limite.

Na página do manual getrlimit(2) :

RLIMIT_NPROC The maximum number of processes (or, more precisely on Linux, threads) that can be created for the real user ID of the calling process. Upon encountering this limit, fork(2) fails with the error EAGAIN.

O mesmo que para pthread_create(3) :

EAGAIN Insufficient resources to create another thread, or a system-imposed limit on the number of threads was encountered. The latter case may occur in two ways: the RLIMIT_NPROC soft resource limit (set via setrlimit(2)), which limits the number of process for a real user ID, was reached; or the kernel's system-wide limit on the number of threads, /proc/sys/kernel/threads-max, was reached.

Aumente esse limite para seu usuário e ele poderá criar mais encadeamentos até atingir outros limites de recursos.
Ou exaustão de recursos simples - para pilha de 1 Mb e threads de 20k, você precisará de muita memória RAM. Consulte também NPTL encapsula os encadeamentos máximos em 65528? : /proc/sys/vm/max_map_count pode se tornar um questão em algum momento.

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

    
por 09.09.2012 / 08:09
0

Nós nos deparamos com esse problema quando problemas de conexão do cliente mongo (java) foram interrompidos (parece que a rede da AWS). Com o TCP_KEEPALIVE configurado para 7200 (2 horas), as conexões nos conjuntos de conexão são construídas dentro dessa janela de 2 horas e o mongod é interrompido quando atinge 975 conexões.

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

    
por 19.04.2013 / 11:09