Cuando nos referimos a ficheros abiertos, realmente nos referimos a descriptores de ficheros abiertos, los cuales no tienen que ser necesariamente archivos tal y como los conocemos.
Un descriptor de archivo es una clave a una estructura de datos residente en el núcleo, que contiene detalles de todos los archivos abiertos. En POSIX, esta estructura de datos se llama “tabla de descriptores de archivos”, y cada proceso tiene la suya. La aplicación que lanza un usuario pasa al núcleo la clave abstracta mediante una llamada al sistema, y el núcleo accede al archivo correspondiente a la clave. Esa misma aplicación no puede acceder a la tabla de descriptores de archivo directamente, ni para leer ni para escribir.
En los sistemas Unix, los descriptores de archivo se pueden referir a archivos, directorios, dispositivos de bloques o dispositivos de caracteres (también llamados “archivos especiales”), sockets, FIFOs (también llamados “tuberías con nombre”) o tuberías sin nombre. El kernel es el encargado de establecer el número máximo de archivos que puede asignar a procesos, esto lo hace por medio del valor de “fs.file-max”, el cual es modificable si se necesita.
Establecer de forma persistente el límite de descriptores de fichero (/etc/sysctl.conf) a manejar del kernel.
fs.file-max = 1000000
Si se modifica el valor, se deben guardar los cambios y comprobar que el valor es el esperado.
sysctl -p
sysctl fs.file-max
Se puede consultar el valor en el fichero /proc/sys/fs/file-max y /proc/sys/fs/file-nr.
cat /proc/sys/fs/file-nr 3936 0 707452
El fichero file-nr muestra tres parámetros. 3936 Descriptores de ficheros asignados. 0 Descriptores de ficheros que no están en uso pero fueron asignados. 707452 Límite de descriptores de ficheros del sistema del sistema (/proc/sys/fs/file-max).
El núcleo asigna dinámicamente descriptores de archivo cada vez que es solicitado por una aplicación, pero el núcleo no los libera cuando la aplicación ha terminado de utilizarlo. El kernel recicla estos identificadores de archivo en su lugar. Esto significa que con el tiempo el número total de descriptores asignados aumentará a pesar de que el número de descriptores de archivo que se utilizan en el momento puede ser bajo.
Además de los límites establecidos por el núcleo, se permite definir políticas por proceso / usuario, estos límites pueden ser duros o blandos. Los límites se aplican a procesos y no a usuarios, un usuario que tenga un límite de 1024 descriptores de ficheros, puede arrancar tres aplicaciones y por tanto, entre ellas tener un máximo de 3072 ficheros abiertos.
Tipos de límite de ficheros abiertos: duros y blandos.
- Un límite duro determina el máximo número de ficheros abiertos permitido a un proceso de usuario, solo puede ser establecido por root.
- Un límite blando es el límite establecido a un usuario, puede en momentos de necesidad ser aumentado por el propio usuario / proceso. Tiene como máximo ese límite duro establecido por root.
Cantidad máxima de ficheros abiertos por usuario y sesión.
ulimit -n 1024
Mostrar los límites blandos y duros del usuario en uso.
# ulimit -Sn 1024 # ulimit -Hn 1024
Modificar límite de ficheros abiertos simultáneamente en un sistema.
# Modificar los dos límites (S/H)con un solo comando. ulimit -SHn 10000 # Modificar los límites de forma separada ulimit -Hn 10000 ulimit -Sn 10000 # Recordemos que el valor podría ser menor si se desea
NOTA: El límite suave (“Sn”) nunca puede ser mayor que el duro (“Hn”).
Estos cambios no son persistentes y duran lo que dure la sesión de ese usuario en el sistema.
Si se están usando systemd, los límites establecidos en el fichero limits.conf serán ignorados ya que systemd usa su propios límites. Por lo tanto, para servicios administrados por systemd se deben especificar en el mismo fichero .service.
Relación entre “systemd limits” y “ulimit”.
Directive ulimit equivalent Unit LimitCPU= ulimit -t Seconds LimitFSIZE= ulimit -f Bytes LimitDATA= ulimit -d Bytes LimitSTACK= ulimit -s Bytes LimitCORE= ulimit -c Bytes LimitRSS= ulimit -m Bytes LimitNOFILE= ulimit -n Number of File Descriptors LimitAS= ulimit -v Bytes LimitNPROC= ulimit -u Number of Processes LimitMEMLOCK= ulimit -l Bytes LimitLOCKS= ulimit -x Number of Locks LimitSIGPENDING= ulimit -i Number of Queued Signals LimitMSGQUEUE= ulimit -q Bytes LimitNICE= ulimit -e Nice Level LimitRTPRIO= ulimit -r Realtime Priority LimitRTTIME= No equivalent
Si con ulimit se utiliza 'unlimited' equivale a 'infinity' en systemd.
ulimit -c unlimited = LimitCORE=infinity ulimit -v unlimited = LimitAS=infinity ulimit -m unlimited = LimitRSS=infinity
Ejemplo (Bloque [Service]).
[Unit] Description=... ... [Service] LimitNPROC=8192:16384 LimitNOFILE=90000:110000 LimitCORE=500M # Permite crear coredumps hasta 500M. [Install] ...
Hay otros ficheros para configurar los límites de una manera más global.(Leer).
/etc/systemd/system.conf /etc/systemd/user.conf /etc/systemd/<systemd_unit>/override.conf
En sistemas sin systemd, como es SysV, los cambios permanentes sobre los límites de ficheros abiertos se realizan sobre /etc/security/limits.conf (soft y hard).
* soft nofile 4096 * hard nofile 4096
NOTA: El patrón “*” se refiere a todos los usuarios, también se puede definir por usuario.
Consultar límites de ficheros abiertos de otros usuarios.
su USUARIO --shell /bin/bash --command "ulimit -Hn"
Ver número de ficheros abiertos de un determinado proceso en ejecución. (ej. 709)
cat /proc/709/limits | grep -i open Max open files 1024 4096 files
Dos opciones para incrementar el límite de descriptores de ficheros abiertos en tiempo de ejecución.
Opción 1.
# echo -n "Max open files=soft:hard" > /proc/pid/limits echo -n "Max open files=4096:4096" > /proc/$pid/limits
NOTA: Depende del núcleo en uso puede funcionar o no.
Opción 2.
prlimit -n1111:12222 -n -p 709 cat /proc/709/limits | grep -i open Max open files 1111 12222 files
NOTA: prlimit permite a su vez cambiar muchos otros límites de procesos, al final de la guía se encuentra su manual.
lsof: Conocer qué ficheros están en uso (abiertos) por determinados programas.
Mostrar todos los ficheros abiertos del sistema.
lsof
Ficheros abiertos por aplicación / proceso / programa.
lsof -c java
Ficheros abiertos por usuario
lsof -u rita
Saber qué programa tiene abierto un determinado fichero.
lsof /opt/atlassian/stash_4.5.0/logs/localhost.2018-09-30.log COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME java 23131 atlstash 8w REG 253,1 33422 5505385 /opt/atlassian/stash_4.5.0/logs/localhost.2018-09-30.log
Visualizar qué ficheros de un directorio están abiertos por programas.
lsof +D /opt/atlassian/stash_4.5.0/logs/
Opciones del comando ulimit.
El comando “ulimit” proporciona control sobre los recursos disponibles para el interprete de comandos (shell) y sus procesos iniciados. ulimit marca los límites por cada proceso que el usuario ejecuta, cada proceso no podrá tener más de X ficheros abiertos.
Prueba de concepto
usuario:~ $ ulimit -n 1024 # Ficheros abiertos por todos los procesos del usuario (cada proceso solo puede tener 1024). usuario:~ $ lsof | grep -i usuario | wc -l 28190
prlimit: Utilidad para modificar / visualizar los límites de uno o varios procesos dados.
NOTA: El parámetro memlock debe estar a “unlimited” si se quiere usar Huge Pages (Típico en bases de datos base de datos). También se recomienda para el uso de aplicaciones nosql como ElasticSearch.
Consulta y modificación del parámetro memlock con ulimit (64 > ulimit).
ulimit -l unlimited 64 ulimit -l unlimited ulimit -l unlimiled<code> <code>Modo de empleo: prlimit [opciones] [-p PID] prlimit [opciones] ORDEN Muestra o modifica los límites de recursos de un proceso. Opciones generales: -p, --pid <pid> id del proceso -o, --output <lista> define las columnas que se usarán en la salida --noheadings no imprime las cabeceras --raw utiliza el formato de salida en bruto --verbose salida con explicaciones -h, --help muestra esta ayuda y termina -V, --version saca información sobre la versión y termina Opciones de los recursos: -c, --core tamaño máximo de los ficheros «core» que se generen -d, --data tamaño máximo del segmento de datos de los procesos -e, --nice máxima prioridad «nice» que se permite elevar -f, --fsize tamaño máximo de los ficheros escritos por el proceso -i, --sigpending número máximo de señales pendientes -l, --memlock tamaño máximo que un proceso puede bloquear en la memoria -m, --rss tamaño máximo de conjunto residente -n, --nofile número máximo de ficheros abiertos -q, --msgqueue número máximo de bytes en colas de mensajes POSIX -r, --rtprio máxima prioridad de planificación en tiempo real -s, --stack tamaño máximo de pila -t, --cpu cantidad de tiempo de CPU máxima en segundos -u, --nproc número máximo de procesos de usuario -v, --as tamaño de la memoria virtual -x, --locks número máximo de bloqueos de fichero -y, --rttime tiempo de CPU en microsegundos planificado por un proceso bajo planificación en tiempo real Columnas disponibles (para --output): DESCRIPTION descripción del recurso RESOURCE nombre de recurso SOFT límite blando HARD límite duro (techo) UNITS unidades
Ejecutar “prilimit” en distribuciones antiguas (util-linux =< 2.20).
Si no se dispone del comando “prlimit” / el paquete util-linux (>= 2.21) para instalar desde repositorios, la única solución es compilar “util-linux”. Si solo se desea disponer del comando se puede utilizar la siguiente compilación para no necesitar muchas dependencias.
wget https://www.kernel.org/pub/linux/utils/util-linux/v2.22/util-linux-2.22.2.tar.gz tar -zxvf util-linux-2.22.2.tar.gz cd util-linux-2.22.2/ ./configure --without-ncurses --disable-su --disable-sulogin --disable-login make ./prlimit