Socket accept – “Demasiados archivos abiertos”

7 minutos de lectura

avatar de usuario
scott

Estoy trabajando en un proyecto escolar en el que tuve que escribir un servidor de subprocesos múltiples, y ahora lo estoy comparando con apache ejecutando algunas pruebas en su contra. Estoy usando autobench para ayudar con eso, pero después de ejecutar algunas pruebas, o si le doy una tasa demasiado alta (alrededor de 600+) para hacer las conexiones, aparece el error “Demasiados archivos abiertos”.

Una vez que he terminado de tratar con la solicitud, siempre hago una close() en el zócalo. He intentado usar el shutdown() funcionar también, pero nada parece ayudar. ¿Alguna forma de evitar esto?

Hay varios lugares donde Linux puede tener límites en la cantidad de descriptores de archivos que puede abrir.

Puedes comprobar lo siguiente:

cat /proc/sys/fs/file-max

Eso le dará al sistema amplios límites de descriptores de archivos.

En el nivel de caparazón, esto le indicará su límite personal:

ulimit -n

Esto se puede cambiar en /etc/security/limits.conf – es el parámetro nofile.

Sin embargo, si está cerrando sus sockets correctamente, no debería recibir esto a menos que esté abriendo muchas conexiones simultáneas. Parece que algo impide que los enchufes se cierren correctamente. Me gustaría verificar que se están manejando correctamente.

  • nombre de usuario duro nofile 20000

    – linjunhalida

    21 de julio de 2011 a las 7:39

avatar de usuario
Mella

Tuve un problema similar. La solución rápida es:

ulimit -n 4096

La explicación es la siguiente: cada conexión de servidor es un descriptor de archivo. En CentOS, Redhat y Fedora, probablemente otros, el límite de usuarios de archivos es 1024, no tengo idea de por qué. Se puede ver fácilmente cuando escribe: ulimit -n

Tenga en cuenta que esto no tiene mucha relación con los archivos máximos del sistema (/proc/sys/fs/file-max).

En mi caso fue un problema con Redis, así que hice:

ulimit -n 4096
redis-server -c xxxx

en su caso, en lugar de redis, debe iniciar su servidor.

  • Y la respuesta a una pérdida de memoria es… ¿comprar más memoria? No arreglar la fuga de archivos.

    –Rafael Bautista

    21 mayo 2013 a las 15:56

  • Parece que no entiende el problema (¿o coloca el comentario en la respuesta incorrecta? Tiene que ver con el límite del descriptor de archivo y no tiene nada que ver con la memoria o la fuga de memoria.

    – Nick

    21 de mayo de 2013 a las 17:48

  • El límite de archivos es 1024 porque de lo contrario te encuentras con un problema fundamental con select().

    – esponjoso

    08/08/2014 a las 18:40

  • @RafaelBaptista En realidad, se necesita una gran cantidad de conexiones simultáneas en algunos casos, como por ejemplo, un servidor de chat de alto rendimiento. Esto no tiene que ser sobre fugas de FD.

    – Antwan van Houdt

    3 de junio de 2016 a las 10:43

  • @RafaelBaptista: si tiene un servidor que puede manejar más de 512 conexiones paralelas, necesita MUCHOS MÁS archivos abiertos. Los servidores modernos pueden manejar varios millones de conexiones paralelas, por lo que tener un límite tan bajo como 1024 realmente no tiene ningún sentido. Podría estar bien para el límite predeterminado para usuarios ocasionales, pero no para el software del servidor que maneja conexiones de clientes paralelos.

    –Mikko Rantalainen

    7 de abril de 2020 a las 7:06


TCP tiene una función llamada “TIME_WAIT” que garantiza que las conexiones se cierren limpiamente. Requiere que un extremo de la conexión permanezca escuchando durante un tiempo después de que se haya cerrado el zócalo.

En un servidor de alto rendimiento, es importante que sean los clientes los que entren en TIME_WAIT, no el servidor. Los clientes pueden permitirse tener un puerto abierto, mientras que un servidor ocupado puede quedarse rápidamente sin puertos o tener demasiados FD abiertos.

Para lograr esto, el servidor nunca debe cerrar la conexión primero; siempre debe esperar a que el cliente la cierre.

  • No. TCP TIME_WAIT mantendrá abiertos los sockets en el nivel del sistema operativo y eventualmente hará que el servidor rechace las conexiones entrantes. Cuando cierra el identificador del archivo, está cerrado. stackoverflow.com/questions/1803566/…

    –Rafael Bautista

    21 mayo 2013 a las 15:57

  • Es cierto que el identificador del archivo se cierra inmediatamente y me expresé mal. Pero mi punto principal sigue en pie, porque a pesar de que se libera el FD, el puerto TCP permanece asignado durante TIME_WAIT, y un servidor ocupado puede quedarse sin puertos TCP o gastar demasiada memoria del núcleo rastreándolos.

    – Ed4

    08/04/2015 a las 17:10

avatar de usuario
edson medina

Utilizar lsof -u `whoami` | wc -l para encontrar cuántos archivos abiertos tiene el usuario

avatar de usuario
shilovk

Esto significa que el número máximo de archivos abiertos simultáneamente.

Resuelto:

Al final del archivo /etc/security/limits.conf necesita agregar las siguientes líneas:

* soft nofile 16384
* hard nofile 16384

En la consola actual desde la raíz (sudo no funciona) para hacer:

ulimit -n 16384

Aunque esto es opcional, si es posible reiniciar el servidor.

En /etc/nginx/nginx.conf archivo para registrar el nuevo valor worker_connections igual a 16384 dividir por valor worker_processes.

si no lo hizo ulimit -n 16384necesita reiniciar, entonces el problema desaparecerá.

PD:

Si después de la reparación es visible en los registros error accept() failed (24: Too many open files):

En la configuración de nginx, propevia (por ejemplo):

worker_processes 2;

worker_rlimit_nofile 16384;

events {
  worker_connections 8192;
}

avatar de usuario
Rafael Bautista

También tuve este problema. Tiene una fuga de identificador de archivo. Puede depurar esto imprimiendo una lista de todos los identificadores de archivos abiertos (en sistemas POSIX):

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

Al deshacerse de todos los archivos abiertos, descubrirá rápidamente dónde está la fuga del identificador de archivos.

Si su servidor genera subprocesos. Por ejemplo, si este es un servidor de estilo ‘fork’, o si está generando otros procesos (por ejemplo, a través de cgi), debe asegurarse de crear sus identificadores de archivo con “cloexec”, tanto para archivos reales como para sockets.

Sin cloexec, cada vez que bifurca o genera, todos los identificadores de archivos abiertos se clonan en el proceso secundario.

También es muy fácil fallar al cerrar los sockets de la red, por ejemplo, simplemente abandonarlos cuando la parte remota se desconecta. Esto filtrará los mangos como locos.

avatar de usuario
Parcialmente nublado

puede tomar un poco de tiempo antes de que un socket cerrado se libere realmente

lsof para listar archivos abiertos

cat /proc/sys/fs/file-max para ver si hay un límite del sistema

¿Ha sido útil esta solución?

Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos y para mostrarte publicidad relacionada con sus preferencias en base a un perfil elaborado a partir de tus hábitos de navegación. Al hacer clic en el botón Aceptar, acepta el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Configurar y más información
Privacidad