15%

Ahorra 15%<\/span> en todos los servicios de hosting

Pon a prueba tus habilidades y obtén Descuento<\/span> en cualquier plan de hosting

Usa el código:

Skills
Comenzar
09.10.2024

Gestión de recursos del sistema con el comando `ulimit` en Linux

El comando `ulimit` es una utilidad de shell integrada en sistemas Unix y Linux que aplica límites de recursos por proceso y por usuario, evitando que un solo proceso o usuario agote los recursos del sistema, como el tiempo de CPU, la memoria, los descriptores de archivos abiertos y el recuento de procesos. Opera a nivel del kernel a través de la llamada al sistema `setrlimit()`, lo que lo convierte en uno de los mecanismos más directos y de bajo coste disponibles para los administradores de sistemas en materia de gestión de recursos.

Para cualquier servidor que ejecute cargas de trabajo en producción — ya sea una aplicación web de alto tráfico, un motor de base de datos o una pila de microservicios en contenedores — las configuraciones de `ulimit` incorrectas o ausentes son una causa principal de fallos en cascada, procesos descontrolados e interrupciones totales del sistema. Configurar correctamente estos límites no es opcional; es una higiene de infraestructura fundamental.

Cómo funciona `ulimit` internamente

Cuando un proceso de shell llama a `ulimit`, invoca las llamadas al sistema `getrlimit()` y `setrlimit()` definidas en el estándar POSIX. Cada límite se representa como un par de valores: un límite blando y un límite duro. Estos se almacenan por proceso en el descriptor de proceso del kernel y son heredados por los procesos hijos en el momento de `fork()`.

Este modelo de herencia es fundamental para comprender. Si establece valores de `ulimit` en una sesión de shell, todos los procesos generados desde ese shell — incluidos los demonios lanzados mediante scripts de inicio — heredan esos límites. Por el contrario, los límites establecidos en `/etc/security/limits.conf` se aplican en el momento del inicio de sesión PAM, no en tiempo de ejecución, lo que significa que solo tienen efecto para las nuevas sesiones de inicio de sesión, no para los servicios que ya están en ejecución.

Límites blandos vs. límites duros

PropiedadLímite blandoLímite duro
Quién puede aumentarloCualquier usuario sin privilegios (hasta el límite duro)Solo root (`CAP_SYS_RESOURCE`)
Quién puede reducirloCualquier usuarioCualquier usuario (irreversible sin root)
AplicaciónAplicado por el kernelActúa como techo para el límite blando
Caso de uso típicoLímite operativo del día a díaMáximo absoluto para la política de seguridad
Indicador en `ulimit``-S``-H`

Un error operativo común es establecer el límite duro igual al límite blando. Esto elimina toda flexibilidad para que un proceso aumente temporalmente sus propios límites, algo que algunas aplicaciones (como ciertas implementaciones de JVM y motores de bases de datos) hacen legítimamente durante el inicio.

Referencia completa: indicadores de recursos de `ulimit`

IndicadorRecursoUnidadValor común en producción
`-t`Tiempo de CPUSegundos`unlimited` para demonios
`-f`Tamaño máximo de archivoBloques de 512 bytes`unlimited` o límite específico
`-d`Tamaño del segmento de datos (heap)KB`unlimited` para aplicaciones Java
`-s`Tamaño de la pilaKB`8192` (predeterminado)
`-c`Tamaño del archivo de volcado de núcleoBloques de 512 bytes`0` (desactivado en producción)
`-m`Tamaño máximo del conjunto residenteKBRaramente aplicado (usar cgroups)
`-v`Memoria virtual (espacio de direcciones)KB`unlimited` para la mayoría de los servicios
`-n`Descriptores de archivos abiertosCantidad`65536` o más para servidores con mucho tráfico
`-u`Máximo de procesos de usuarioCantidad`4096`–`65536` según el rol
`-l`Memoria bloqueada (mlock)KBAlto para Redis, Elasticsearch
`-i`Señales pendientesCantidadEl valor predeterminado del sistema suele ser suficiente
`-q`Bytes de cola de mensajes POSIXBytesValor predeterminado del sistema
`-r`Prioridad de planificación en tiempo realPrioridad`0` salvo cargas de trabajo RT
`-e`Prioridad máxima de planificación (nice)Valor niceValor predeterminado del sistema

Uso práctico de `ulimit` con contexto del mundo real

Visualización de los límites actuales

“`bash

ulimit -a # All soft limits for the current shell

ulimit -aH # All hard limits for the current shell

“`

Para inspeccionar los límites de un proceso en ejecución específico (PID), lea directamente desde el sistema de archivos proc — esta es la fuente autorizada y omite los informes a nivel de shell:

“`bash

cat /proc/<PID>/limits

“`

Esto es invaluable al solucionar problemas de un servicio iniciado por systemd o un script de inicio, donde `ulimit -a` a nivel de shell no reflejará los límites reales del proceso.

Establecimiento de límites blandos y duros

“`bash

Set soft limit for open file descriptors

ulimit -Sn 65536

Set hard limit for open file descriptors

ulimit -Hn 131072

Set both simultaneously (soft = hard = value)

ulimit -n 65536

“`

Desactivación de volcados de núcleo en producción

“`bash

ulimit -c 0

“`

Los volcados de núcleo pueden consumir gigabytes de espacio en disco en segundos cuando falla un proceso con mucha memoria. Desactivarlos en producción es una práctica estándar a menos que esté depurando activamente. Para entornos de desarrollo, establezca una ruta dedicada usando `sysctl kernel.core_pattern` junto con un límite de núcleo distinto de cero.

Restricción del tiempo de CPU para procesos no confiables

“`bash

ulimit -t 30

“`

Esto envía `SIGXCPU` al proceso cuando alcanza el límite blando de tiempo de CPU, y `SIGKILL` en el límite duro. Esto es particularmente útil en entornos de alojamiento compartido o al ejecutar scripts enviados por usuarios.

Aumento del límite de descriptores de archivos abiertos para servicios de alta concurrencia

Nginx, HAProxy, PostgreSQL y Redis requieren un gran número de descriptores de archivos abiertos bajo carga. El valor predeterminado del sistema de 1024 es peligrosamente bajo para producción:

“`bash

ulimit -n 65536

“`

Sin embargo, esto solo afecta a la sesión de shell actual. Para una configuración persistente, utilice los métodos descritos en la siguiente sección.

Cómo hacer persistentes las configuraciones de `ulimit`

Método 1: `/etc/security/limits.conf`

Este es el enfoque estándar basado en PAM para límites persistentes a nivel de usuario:

“`

/etc/security/limits.conf

<domain> <type> <item> <value>

  • soft nofile 65536
  • hard nofile 131072

nginx soft nproc 4096

nginx hard nproc 8192

postgres soft nofile 65536

postgres hard nofile 65536

postgres soft memlock unlimited

postgres hard memlock unlimited

“`

El comodín `*` se aplica a todos los usuarios pero no se aplica a root. Root requiere una entrada explícita:

“`

root soft nofile 65536

root hard nofile 131072

“`

Asegúrese de que el módulo PAM esté cargado. Verifique que `/etc/pam.d/common-session` (Debian/Ubuntu) o `/etc/pam.d/system-auth` (RHEL/CentOS) contenga:

“`

session required pam_limits.so

“`

Método 2: archivos adicionales de `/etc/security/limits.d/`

Para una gestión más ordenada, especialmente en sistemas de gestión de configuración como Ansible o Puppet, coloque archivos de límites específicos del servicio en el directorio adicional:

“`bash

/etc/security/limits.d/99-nginx.conf

nginx soft nofile 65536

nginx hard nofile 131072

“`

Los archivos en este directorio se procesan después de `limits.conf` y lo anulan, lo que los hace ideales para el ajuste específico de aplicaciones sin modificar la configuración base.

Método 3: unidades de servicio systemd (el estándar moderno)

Para los servicios gestionados por systemd — que es la mayoría de las distribuciones modernas de Linux — `limits.conf` no se aplica de forma predeterminada. systemd gestiona sus propios límites de recursos por unidad de servicio:

“`ini

/etc/systemd/system/nginx.service.d/limits.conf

[Service]

LimitNOFILE=65536

LimitNPROC=4096

LimitCORE=0

LimitMEMLOCK=infinity

“`

Después de editar, recargue y reinicie:

“`bash

systemctl daemon-reload

systemctl restart nginx

“`

Verifique los límites aplicados:

“`bash

cat /proc/$(systemctl show -p MainPID nginx | cut -d= -f2)/limits

“`

Este es el método más fiable para los servicios en producción y debería ser el enfoque predeterminado en cualquier sistema que ejecute systemd (Ubuntu 16.04+, CentOS 7+, Debian 8+).

Método 4: archivos de perfil de shell

Para los límites de sesión de usuario que se aplican de forma interactiva, añada comandos `ulimit` a `/etc/profile` (para todo el sistema) o `~/.bashrc` / `~/.profile` (por usuario). Este enfoque es adecuado para estaciones de trabajo de desarrolladores, pero no es apropiado para procesos de demonio.

Perfiles de configuración de `ulimit` basados en roles

Los diferentes roles de servidor requieren perfiles de límites de recursos fundamentalmente distintos. Aplicar valores predeterminados genéricos en todos los tipos de servidores es una fuente común de fallos sutiles y difíciles de diagnosticar.

Servidor web (Nginx / Apache)

“`

nofile: 65536–131072 # High concurrency requires many open sockets + files

nproc: 4096 # Worker processes + threads

core: 0 # Disable core dumps in production

“`

Base de datos relacional (PostgreSQL / MySQL)

“`

nofile: 65536 # Many concurrent connections = many file descriptors

memlock: unlimited # Required for shared memory and huge pages

nproc: 4096

stack: 8192 KB

core: 0

“`

Servidor de aplicaciones Java (Tomcat / Spring Boot)

“`

nofile: 65536

nproc: 65536 # JVM thread-per-connection models spawn many threads

data: unlimited # JVM heap is allocated from the data segment

stack: 512 KB # Reduce stack size to fit more threads in memory

“`

Redis / almacén de datos en memoria

“`

nofile: 65536

memlock: unlimited # Prevents swapping of memory-mapped data

“`

Errores críticos y casos límite

El límite `nproc` cuenta hilos, no solo procesos. En Linux, los hilos se implementan como procesos ligeros (`clone()` con memoria compartida). Una aplicación Java con 500 hilos cuenta como 500 contra el límite `nproc`. Esto sorprende a muchos administradores que establecen valores conservadores de `nproc` y luego se preguntan por qué su JVM falla con `OutOfMemoryError: unable to create new native thread`.

`ulimit -v` limita el espacio de direcciones virtuales, no la RAM física. Muchos administradores establecen `-v` pensando que están limitando el uso de memoria. En realidad, están limitando el espacio de direcciones virtuales, que incluye archivos mapeados en memoria, bibliotecas compartidas y el metaespacio de JVM. Establecer este valor demasiado bajo causará fallos de `mmap()` y errores crípticos en las aplicaciones.

`ulimit` no se aplica de forma retroactiva. Cambiar los límites en `limits.conf` o en un archivo de unidad systemd no afecta a los procesos que ya están en ejecución. Debe reiniciar el servicio para que los nuevos límites surtan efecto.

Los entornos de contenedores omiten `ulimit` de formas inesperadas. En Docker, los valores predeterminados de `ulimit` se establecen a nivel del demonio (`/etc/docker/daemon.json`) y pueden anularse por contenedor con `–ulimit`. Sin embargo, los límites del contenedor están acotados por los límites del kernel del host. Establecer `nofile=1048576` en un contenedor mientras el host tiene `nofile=65536` volverá silenciosamente al límite del host.

El techo del sistema `nofile` es independiente de los límites por proceso. El parámetro del kernel `fs.file-max` (establecido mediante `sysctl`) controla el número total de descriptores de archivos en todo el sistema. Incluso si `nofile` por proceso está configurado alto, alcanzar `fs.file-max` causará errores de `ENFILE` en todo el sistema. Verifique y ajuste ambos:

“`bash

sysctl fs.file-max

sysctl -w fs.file-max=2097152

“`

`ulimit` vs. cgroups: elegir la herramienta adecuada

Capacidad`ulimit` / `setrlimit`cgroups v2
AlcancePor proceso (heredado por los hijos)Por grupo de procesos
Limitación de memoriaSolo espacio de direcciones virtuales (`-v`)Aplicación real de RSS + swap
Limitación de CPUPresupuesto de tiempo de CPU (`-t`)Controlador de ancho de banda de CPU (% preciso)
Limitación de E/SNo compatiblePeso de E/S de bloque y límites de velocidad
Limitación de redNo compatibleRequiere integración de tc + cgroup
PersistenciaMediante PAM o systemdMediante segmentos systemd o cgroupfs
Compatibilidad con contenedoresLimitadaNativa (Docker, Kubernetes usan cgroups)
GranularidadGruesaDetallada

`ulimit` sigue siendo la herramienta adecuada para límites rápidos por sesión, límites de descriptores de archivos y control de volcados de núcleo. Para un aislamiento de recursos completo — especialmente en entornos multiinquilino o cargas de trabajo en contenedores — cgroups v2 es el mecanismo superior. En un entorno de Alojamiento VPS o Servidor Dedicado bien configurado, ambos mecanismos se utilizan normalmente en combinación: `ulimit` para barreras por proceso y cgroups para presupuestos de recursos agregados.

Monitorización y validación de los límites de recursos

La monitorización proactiva evita que los fallos relacionados con los límites se conviertan en incidentes de producción.

Compruebe el uso actual de descriptores de archivos en todo el sistema:

“`bash

cat /proc/sys/fs/file-nr

Output: <allocated> <unused> <max>

“`

Encuentre procesos que se acercan a su límite `nofile`:

“`bash

for pid in /proc/[0-9]*; do

pid_num=${pid##*/}

limit=$(awk '/Max open files/{print $4}' /proc/$pid_num/limits 2>/dev/null)

current=$(ls /proc/$pid_num/fd 2>/dev/null | wc -l)

[ -n "$limit" ] && [ "$limit" != "unlimited" ] &&

awk -v c=$current -v l=$limit -v p=$pid_num

'BEGIN{if(c/l>0.8) printf "PID %s: %d/%d (%.0f%%)n",p,c,l,c/l*100}'

done

“`

Herramientas para la monitorización continua:

  • `lsof -u <username>` — lista todos los archivos abiertos de un usuario
  • `ss -s` — estadísticas de sockets (se correlaciona con la presión de `nofile`)
  • `htop` con vista de árbol de procesos — visualiza el recuento de procesos por usuario
  • `sar -v` — uso histórico de descriptores de archivos e inodos mediante sysstat
  • `node_exporter` de Prometheus — expone métricas de `node_filefd_allocated` y `node_filefd_maximum` para alertas

Para entornos que ejecutan VPS con cPanel u otros paneles de control, muchos de estos límites están preconfigurados por el instalador del panel, pero con frecuencia necesitan ajustarse al alza a medida que crece el tráfico. Verifique siempre los límites reales con `/proc/<PID>/limits` en lugar de confiar en la documentación del panel.

Implicaciones de seguridad de `ulimit`

Los límites de recursos también son un control de seguridad. Sin ellos, un proceso comprometido o con errores puede ejecutar una bomba fork (`:(){ :|:& };:`), agotando todos los espacios de proceso disponibles y dejando el sistema sin respuesta. Un límite conservador de `nproc` por usuario es la mitigación principal:

“`

  • hard nproc 4096

“`

Del mismo modo, deshabilitar los volcados de núcleo (`-c 0`) evita que el contenido sensible de la memoria — incluidas claves de cifrado, contraseñas y tokens de sesión — se escriba en disco en un archivo legible por todos.

Para entornos de alojamiento compartido o cualquier servidor donde múltiples usuarios tienen acceso al shell, `ulimit` es una capa de seguridad obligatoria. En la infraestructura de Alojamiento Web Compartido, estos límites suelen aplicarse a nivel de plataforma, pero los administradores que ejecutan su propio VPS multiusuario deben configurarlos explícitamente.

Si su servidor gestiona la terminación SSL o la gestión de certificados, asegúrese de que el proceso que maneja TLS (por ejemplo, Nginx, HAProxy) tenga límites de `nofile` suficientes, ya que cada conexión TLS requiere múltiples descriptores de archivos. Combínelo con Certificados SSL correctamente configurados para evitar que los fallos relacionados con certificados agraven los problemas de recursos.

Para implementaciones de servidores de correo, Postfix y Dovecot son especialmente sensibles a los límites de `nofile`, ya que cada conexión de correo electrónico simultánea y acceso a buzón consume descriptores de archivos. Si está ejecutando su propia infraestructura de correo en lugar de utilizar Alojamiento de Correo gestionado, ajustar `nofile` a al menos 65536 para el usuario de correo es innegociable en cualquier servidor con carga moderada.

Matriz de decisión: qué configurar y dónde

EscenarioMétodo recomendadoParámetros clave
Sesiones de usuario interactivas`/etc/security/limits.conf``nofile`, `nproc`, `core`
Servicio gestionado por systemdSección `[Service]` de la unidad systemd`LimitNOFILE`, `LimitNPROC`, `LimitCORE`
Contenedor DockerIndicador `–ulimit` o `daemon.json``nofile`, `nproc`
Pruebas puntuales en shellComando `ulimit` directamenteCualquier indicador
Servidor compartido multiinquilino`limits.conf` + aplicación PAM`nproc`, `nofile`, `fsize`, `cpu`
Pod de KubernetesContexto de seguridad del pod + cgroupsGestionado por kubelet
Ajuste específico de aplicaciónArchivo adicional `limits.d/`Parámetros específicos del servicio

Lista de verificación de puntos clave técnicos

  • Verifique siempre los límites aplicados mediante `/proc/<PID>/limits`, no mediante `ulimit -a` a nivel de shell, para los servicios en ejecución.
  • Para los servicios systemd, configure los límites en el archivo de unidad usando directivas `Limit*` — `limits.conf` no es leído por systemd de forma predeterminada.
  • Establezca `nofile` en un mínimo de `65536` para cualquier servicio que gestione conexiones de red; `131072` o más para cargas de trabajo de alta concurrencia.
  • Nunca establezca el límite duro igual al límite blando a menos que tenga un requisito de seguridad específico — las aplicaciones necesitan margen para autoajustarse.
  • Deshabilite los volcados de núcleo (`LimitCORE=0`) en producción; actívelos con una ruta controlada en entornos de prueba.
  • El límite `nproc` cuenta hilos en Linux — téngalo en cuenta al configurar aplicaciones JVM o de tiempo de ejecución Go.
  • Ajuste `fs.file-max` mediante `sysctl` junto con los límites de `nofile` por proceso para evitar el agotamiento de `ENFILE` en todo el sistema.
  • En entornos en contenedores, los límites del kernel del host son el techo máximo — las configuraciones de `ulimit` a nivel de contenedor no pueden superarlos.
  • Use cgroups v2 para la aplicación de memoria y E/S; use `ulimit` para límites de descriptores de archivos, recuentos de procesos y control de volcados de núcleo.
  • Después de cualquier cambio de límite en `limits.conf` o en archivos de unidad systemd, reinicie el servicio afectado y verifique con `/proc/<PID>/limits`.

Preguntas frecuentes

¿Se aplica `ulimit` a los procesos root?

El comodín `*` en `/etc/security/limits.conf` excluye explícitamente a root. Los procesos root también omiten la aplicación de límites duros para la mayoría de los tipos de recursos — root puede aumentar sus propios límites duros. Para aplicar límites a root, añada una entrada explícita de `root` en `limits.conf`, aunque muchos servicios del sistema que se ejecutan como root ignorarán los límites aplicados por PAM si se inician fuera de una sesión de inicio de sesión.

¿Por qué mi cambio en `limits.conf` no tiene efecto en un servicio en ejecución?

`limits.conf` es aplicado por PAM en el momento del inicio de sesión. Los servicios iniciados por systemd, SysVinit o Upstart no pasan por PAM y, por lo tanto, no heredan la configuración de `limits.conf`. Configure los límites directamente en el archivo de unidad systemd usando `LimitNOFILE` y directivas relacionadas, luego ejecute `systemctl daemon-reload && systemctl restart <service>`.

¿Cuál es el valor máximo que puedo establecer para `nofile`?

El máximo por proceso está acotado por el parámetro del kernel `fs.nr_open` (predeterminado: 1.048.576 en la mayoría de los kernels). El total en todo el sistema está acotado por `fs.file-max`. Puede aumentar `fs.nr_open` mediante `sysctl`, pero los valores superiores a 1.048.576 requieren recompilación del kernel en kernels más antiguos. En la práctica, 524.288 o 1.048.576 cubre prácticamente todos los casos de uso en producción.

¿Cómo compruebo si un proceso ha alcanzado su límite de `ulimit`?

Compruebe el registro del kernel con `dmesg | grep -i "ulimit|RLIMIT|too many open|cannot allocate"`. Los registros de la aplicación normalmente mostrarán `EMFILE` (demasiados archivos abiertos), `ENOMEM` (fallo de asignación de memoria) o `EAGAIN` (recurso temporalmente no disponible). Contraste con `/proc/<PID>/limits` y el recuento actual de descriptores mediante `ls /proc/<PID>/fd | wc -l`.

¿Es `ulimit` suficiente para el aislamiento de recursos en un entorno multiinquilino?

No. `ulimit` proporciona barreras por proceso y por usuario, pero no aplica límites de ancho de banda de memoria, E/S de disco o rendimiento de red. Para un aislamiento multiinquilino real, combine `ulimit` con controladores de recursos cgroups v2, y considere el aislamiento de espacios de nombres (espacios de nombres de usuario, espacios de nombres PID) para límites de seguridad más estrictos. En infraestructura gestionada, estos controles suelen estar en capas a nivel del hipervisor y del tiempo de ejecución de contenedores.

15%

Ahorra 15%<\/span> en todos los servicios de hosting

Pon a prueba tus habilidades y obtén Descuento<\/span> en cualquier plan de hosting

Usa el código:

Skills
Comenzar