¿Por qué (o cómo) el número de descriptores de archivos abiertos en uso por root supera ulimit -n?

13

Nuestro servidor recientemente se quedó sin descriptores de archivos, y con respecto a eso tengo algunas preguntas. ulimit -nse supone que me da la cantidad máxima de descriptores de archivo abiertos. Ese número es 1024. Verifiqué la cantidad de descriptores de archivos abiertos ejecutando lsof -u root |wc -ly obtuve 2500 fds. Eso es mucho más que 1024, así que supuse que eso significaría que el número 1024 es por proceso, no por usuario, como lo hice yo. Bueno, corrí lsof -p$PidOfGlassfish|wc -ly obtuve 1300. Esta es la parte que no entiendo. Si ulimit -nno es el número máximo de procesos por usuario o por proceso, ¿para qué sirve? ¿No se aplica al usuario root? Y si es así, ¿cómo podría obtener los mensajes de error sobre la falta de descriptor de archivo?

EDITAR: La única forma en que puedo tener sentido ulimit -nes si aplica la cantidad de archivos abiertos (como se indica en el manual de bash) en lugar de la cantidad de identificadores de archivos (diferentes procesos pueden abrir el mismo archivo). Si este es el caso, simplemente enumerar el número de archivos abiertos (grepping en '/', excluyendo así los archivos mapeados en memoria) no es suficiente:

lsof -u root |grep /|sort  -k9  |wc -l #prints '1738'

Para ver realmente la cantidad de archivos abiertos, necesitaría filtrar en la columna de nombre para imprimir solo las entradas únicas. Por lo tanto, lo siguiente es probablemente más correcto:

lsof -u root |grep /|sort  -k9 -u |wc -l #prints '604'

El comando anterior espera resultados en el siguiente formato de lsof:

java      32008 root  mem       REG                8,2 11942368      72721 /usr/lib64/locale/locale-archive
vmtoolsd   4764 root  mem       REG                8,2    18624     106432 /usr/lib64/open-vm-tools/plugins/vmsvc/libguestInfo.so

Esto al menos me da un número menor que 1024 (el número reportado por ulimit -n), por lo que parece un paso en la dirección correcta. "Desafortunadamente" No estoy experimentando ningún problema con la falta de descriptores de archivos, por lo que me será difícil validar esto.

oligofren
fuente
2
lsof informa asignaciones de memoria, así como archivos abiertos, por lo que su canalización 'wc' produce una sobreestimación del número de descriptores de archivo utilizados por ese proceso.
Richard Kettlewell
aha! Ahora que es buena información. Pero no estoy muy seguro de entender. Por "mapeos de memoria", ¿quiere decir un archivo mapeado de memoria? Eso requeriría un identificador de archivo a mi entender, o ¿de qué otra forma podría el sistema operativo actualizar el archivo?
oligofren
Y seguimiento dos: ¿Cuál sería una buena manera de encontrar todos los identificadores de archivos abiertos, los que en realidad están afectados por los límites impuestos por "ulimit -n"?
oligofren
1
Las asignaciones de memoria no requieren un archivo abierto. Si solo desea listar archivos abiertos, filtrar la salida de lsof es probablemente el enfoque más fácil.
Richard Kettlewell
Gracias, edité mi respuesta. Usar ´lsof -u root | grep / | sort -k9 -u´ parece dar lo que equivale a una respuesta razonable. Esto es al menos un número menor que ulimit -n.
oligofren

Respuestas:

9

Probé esto en Linux versión 2.6.18-164.el5 - Red Hat 4.1.2-46. Pude ver que el ulimit se aplica por proceso.

El parámetro se establece a nivel de usuario, pero se aplica a cada proceso.

Por ejemplo: 1024 era el límite. Se iniciaron múltiples procesos y los archivos abiertos por cada uno se contaron usando

ls -l /proc/--$pid--/fd/ | wc -l

No hubo errores cuando la suma de archivos abiertos por múltiples procesos cruzó 1024. También verifiqué el recuento de archivos únicos combinando los resultados para diferentes procesos y contando archivos únicos. Los errores comenzaron a aparecer solo cuando el recuento de cada proceso cruzó 1024. (java.net.SocketException: demasiados archivos abiertos en los registros de proceso)

Elegido
fuente
Gracias por probar esto. ¿Tienes alguna idea de por qué lsof -p$PidOfGlassfish|wc -lme diste 1300? Supongo que los dos enfoques para contar difieren de alguna manera. Si no es así, ¿tal vez el límite no se aplica al usuario root?
oligofren
Por curiosidad, ¿por qué usar en ls -llugar de ls? Este último tiene una línea adicional (por ejemplo total 5) cuando hay 5 archivos. En tal caso, usar ls -l en el ejemplo anterior informaría 6 no 5. Yo uso ls /proc/<pid>/fd | wc -l.
Starfry
@starfry Eso es solo descuido de mi parte. Normalmente hago esto paso a paso y ls -lme da una entrada por línea, que luego canalizo en otra cosa. Por supuesto, esto también sucede cuando la tubería es normal ls(pero no de otra manera).
oligofren
3

El ulimit es para filehandles. Se aplica a archivos, directorios, sockets, tuberías, epolls, eventfds, timerfds, etc.

En cualquier momento durante el inicio del proceso, los límites pueden haber cambiado. Visite /proc/<pid>/limitsy vea si los valores han sido alterados.

Matthew Ife
fuente
3

@oligofren

También llevé a cabo algunas pruebas para determinar la forma "ulimits -Sn"de "open files"fue aplicada.

  • Al igual que el póster que Elegido mencionó en el enlace , el ulimit for "open files"se aplica por proceso. Para ver cuáles son los límites actuales del proceso:

    cat /proc/__process_id__/limits

  • Para determinar cuántos archivos tiene abierto un proceso, debe usar el siguiente comando:

    lsof -P -M -l -n -d '^cwd,^err,^ltx,^mem,^mmap,^pd,^rtd,^txt' -p __process_id__ -a | awk '{if (NR>1) print}' | wc -l

Explicación de lo anterior y mi método de prueba / resultados

Los "-P -M -l -n"argumentos de lsof simplemente están ahí para hacer que lsof funcione lo más rápido posible. Siéntase libre de sacarlos.

-P - inhibits the conversion of port numbers to port names for network files
-M - disable reporting of portmapper registrations for local TCP, UDP and UDPLITE ports
-l - inhibits the conversion of user ID numbers to login names
-n - inhibits the conversion of network numbers to host names for network files

El "-d '^cwd,^err,^ltx,^mem,^mmap,^pd,^rtd,^txt'"argumento indica lsofque se excluyan los descriptores de archivo de tipo: cwd / err / ltx / mem / mmap / pd / rtd / txt.

Desde la página de manual de lsof:

   FD         is the File Descriptor number of the file or:

                   cwd  current working directory;
                   Lnn  library references (AIX);
                   err  FD information error (see NAME column);
                   jld  jail directory (FreeBSD);
                   ltx  shared library text (code and data);
                   Mxx  hex memory-mapped type number xx.
                   m86  DOS Merge mapped file;
                   mem  memory-mapped file;
                   mmap memory-mapped device;
                   pd   parent directory;
                   rtd  root directory;
                   tr   kernel trace file (OpenBSD);
                   txt  program text (code and data);
                   v86  VP/ix mapped file;

Considero que "Lnn,jld,m86,tr,v86"no es aplicable a Linux y, por lo tanto, no me molesté en agregarlos a la lista de exclusión. No estoy seguro de eso "Mxx".

Si sus aplicaciones utilizan marcas de archivos de memoria asignada / dispositivos a continuación, es posible que desee eliminar "^mem"y "^mmap"de la lista de exclusión.

EDITAR --- comenzar a cortar ---

Editar: encontré el siguiente enlace que indica que:

los archivos .so mapeados en memoria técnicamente no son lo mismo que un identificador de archivo sobre el que la aplicación tiene control. / proc // fd es el punto de medición para los descriptores de archivos abiertos

Entonces, si su proceso utiliza archivos asignados a la memoria, deberá filtrar los archivos * .so.

Además, JVM de Sun registrará archivos jar de mapas

Un archivo JAR mapeado en memoria, en este caso el archivo que contiene las "clases JDK". Cuando asigna un JAR en memoria, puede acceder a los archivos dentro de él de manera muy eficiente (en lugar de leerlo desde el principio cada vez). Sun JVM hará un mapeo de memoria de todos los JAR en el classpath; Si su código de aplicación necesita acceder a un JAR, también puede asignarlo en la memoria.

Así que cosas como tomcat / glassfish también mostrarán archivos jar mapeados en memoria. No he probado si estos cuentan para el "ulimit -Sn"límite.

EDITAR --- cortar final ---

Empíricamente, he encontrado que "cwd,rtd,txt"se no se cuenta con respecto al límite de archivo por proceso (ulimit Sn).

No estoy seguro de si "err,ltx,pd"se cuentan para el límite de archivos, ya que no sé cómo crear identificadores de archivos de estos tipos de descriptores.

El "-p __process_id__"argumento se limita lsofa devolver solo información para lo __process_id__especificado. Elimine esto si desea obtener un recuento de todos los procesos.

El "-a"argumento se usa para AND las selecciones (es decir, los argumentos "-p" y "-d").

La "awk '{if (NR>1) print}'"declaración se utiliza para omitir el encabezado que se lsofimprime en su salida.

Probé usando el siguiente script perl:

File: test.pl
---snip---
#!/usr/bin/perl -w
foreach $i (1..1100) {
  $FH="FH${i}";
  open ($FH,'>',"/tmp/Test${i}.log") || die "$!";
  print $FH "$i\n";
}
---snip---

Tuve que ejecutar el script en el depurador perl para asegurarme de que el script no terminara y lanzara los descriptores de archivo.

Ejecutar: perl -d test.pl

En el depurador de perl, puede ejecutar el programa ingresando cy presionando enter y, si ulimit -Sntiene un valor de 1024 , encontrará que el programa se detiene después de crear el Test1017.logarchivo /tmp.

Si ahora identifica el pid del proceso perl y usa el lsofcomando anterior , verá que también genera 1024 .

Elimine "wc -l"y reemplace con un "less"para ver la lista de archivos que contaban hacia el límite de 1024 . Elimine también el "-d ^....."argumento para ver que los descriptores cwd,txty no cuentan para el límite.rtd

Si ahora ejecuta "ls -l /proc/__process_id__/fd/ | wc -l", verá un valor de 1025 devuelto. Esto se debe a que lsagregó un "total 0"encabezado a su salida que se contó.

Nota:

Para verificar si el sistema operativo se está quedando sin descriptores de archivo, es mejor comparar el valor de:

cat /proc/sys/fs/file-nr | awk '{print $1}'

con

cat /proc/sys/fs/file-max

https://www.kernel.org/doc/Documentation/sysctl/fs.txt documenta qué file-nry qué file-maxsignifica.

Jinesh Choksi
fuente
0

Parece que su razonamiento es algo así como: "Tengo que reducir ese límite para no quedarme sin descriptores preciosos". La verdad es exactamente lo contrario: si su servidor se quedó sin descriptores de archivo, debe elevar ese límite de 1,024 a algo más grande. Para una glassfishimplementación realista , 32,768 es razonable.

Personalmente, siempre elevo el límite a alrededor de 8.192 en todo el sistema: 1.024 es simplemente ridículo. Pero querrás subirglassfish más alto. Compruebe /etc/security/limits.conf. Puede agregar una entrada especial para que el usuario se glassfishejecute como.

David Schwartz
fuente
No estoy seguro de cómo podría interpretarme en el sentido de que :-) Lo que me preguntaba es por qué no parecía aplicarse. Lo estableceré más alto, pero también quiero entender cómo funciona. Si el límite es 1024, ¿cómo podría Glassfish tener 1300 manijas?
oligofren
'lsof -u root | grep / | sort -k9 -u' imprime las entradas únicas del descriptor de archivo. Supongo que el número de líneas de este es el número real al que se aplica ulimit -n.
oligofren
0

Desea echar un vistazo a los límites de todo el sistema establecidos en / proc / sys / fs / file-max y ajustarlo allí (hasta el próximo reinicio) o establecer fs.file-max en sysctl.conf para que sea permanente. Esto podría ser útil: http://www.randombugs.com/linux/tuning-file-descriptors-limits-on-linux.html

rnxrx
fuente
1
Ese comentario sobre bash no es exacto. ulimit impone un conjunto de límites por ID de usuario, para procesos iniciados a través del shell, que es prácticamente todo gracias a cómo se genera el árbol de procesos en Unix como los sistemas operativos. No es bash.
EightBitTony
Lo sentimos, se editará, pero los comentarios sobre los límites amplios del sistema aún se mantienen.
rnxrx
Es muy poco probable que esté alcanzando los límites del sistema. Posible, pero muy poco probable.
David Schwartz
EightBitTony: ulimit no establece ulimit por conjunto de límites de identificación de usuario. Es por proceso cuando se aplican pam_limits. El ulimit que es "por usuario" es el "ulimit -u" "El número máximo de procesos disponibles para un solo usuario"
Sin nombre de usuario
0

Error común al comparar el resultado de una llamada sin procesar con un supuesto límite.

Para el límite global (/ proc / sys / fs / file-max) debe echar un vistazo a / proc / sys / fs / file-nr -> el valor de puño indica lo que se utiliza y el último valor es el límite

El límite de OpenFile es para cada proceso, pero puede definirse en un usuario; consulte el comando "ulimit -Hn" para conocer los límites de usuario y consulte /etc/security/limits.conf para ver las definiciones. Generalmente se aplica con "usuario de la aplicación", por ejemplo: "tomcat": establezca el límite en 65000 para el usuario tomcat que se aplicará en el proceso de Java que ejecuta.

Si desea verificar el límite aplicado en un proceso, obtenga su PID y luego: cat / proc / $ {PID} / limits Si desea verificar cuántos archivos abre un proceso, obtenga su PID y luego: ls -1 / proc / {PID} / fd | wc -l (nota para ls es 'menos uno', no para confundir con 'menos el')

Si desea conocer detalles con lsof pero solo para aquellos que manejan archivos que cuentan para el límite, intente con estos: lsof -p $ {PID} | grep -P "^ (\ w + \ s +) {3} \ d + \ D +" lsof -p $ {PID} -d '^ cwd, ^ err, ^ ltx, ^ mem, ^ mmap, ^ pd, ^ rtd, ^ txt '-a

Observación: los 'archivos' son archivos / pipe / tcp connections / etc.

Tenga en cuenta que a veces probablemente necesite ser root o usar sudo para obtener el resultado correcto de los comandos, sin privilegio, a veces no tiene error, solo menos resultados.

y finalmente, si desea saber a qué 'archivos' en su sistema de archivos se accede mediante un proceso, eche un vistazo a: lsof -p {PID} | grep / | awk '{print $ 9}' | ordenar | uniq

que te diviertas !

Ronan Kerdudou
fuente