Proxmox «Too Many Open Files»: qué límite aumentar y en qué servicio

¿Te fue útil?

“Too many open files” es uno de esos errores que resulta insultante. Linux está haciendo exactamente lo que le indicaste: hacer cumplir límites. Proxmox es sólo el lugar donde lo notas, normalmente a las 2 am, generalmente mientras haces algo “seguro” como una copia de seguridad, una migración o una restauración que no puede esperar.

La solución rara vez es “poner todo a un millón”. La solución es: encontrar el proceso que choca con el techo, aumentar el techo correcto (unidad systemd, límite de usuario, límite del kernel o configuración de la aplicación) y luego demostrar que no acabas de ocultar una fuga de descriptores de archivo que volverá con peor cara la próxima semana.

Qué significa realmente “too many open files” en Proxmox

En Linux, “open files” en realidad significa descriptores de archivo: enteros pequeños que un proceso usa para referirse a recursos abiertos. Sí, archivos regulares. También sockets, tuberías, eventfds, watchers de inotify, nodos de dispositivo, a veces incluso objetos anónimos del kernel expuestos a través de una interfaz de archivo. Cuando ves:

  • EMFILE: el proceso alcanzó su límite de descriptores por proceso
  • ENFILE: el sistema alcanzó un límite global de tabla de archivos (menos común en kernels modernos, pero posible)

En entornos Proxmox, EMFILE es el culpable habitual. Eso significa que un proceso específico —un demonio, una instancia QEMU, un worker de backup, un OSD de Ceph— se quedó sin descriptores. Elevar límites a ciegas puede enmascarar una fuga, pero también puede ser la decisión correcta si tu carga de trabajo necesita legítimamente decenas de miles de fds (piensa en: Ceph, proxies reversos muy concurridos, catálogos de backup enormes o una sola VM con mucho virtio-scsi y actividad de red).

Los límites de descriptores existen en múltiples capas:

  • Límite global del kernel (por ejemplo, fs.file-max): cuántos manejadores de archivo puede asignar todo el sistema.
  • Rlimit por proceso (ulimit / RLIMIT_NOFILE): el tope para un proceso dado.
  • Límites de unidad systemd (LimitNOFILE=): lo que systemd configura para un servicio antes de exec.
  • Límites por usuario (PAM / /etc/security/limits.conf): afecta sesiones de login y servicios iniciados bajo un usuario, pero no necesariamente a servicios del sistema gestionados por systemd a menos que PAM esté involucrado.
  • Límites internos de la aplicación: a veces hay un ajuste dentro del servicio también (configuraciones de Ceph, patrones de apertura de archivos en PBS, etc.).

Proxmox añade una vuelta: muchos de los procesos importantes están gestionados por systemd (pvedaemon, pveproxy, pvestatd, pve-cluster), además de instancias QEMU iniciadas bajo scopes de systemd (según versión y configuración). Así que la solución “correcta” suele ser un override de systemd para una unidad específica, no un cambio global de ulimit que además no se aplica a servicios.

Guía rápida de diagnóstico (primeras/segundas/terceras comprobaciones)

Esta es la parte que ejecutas cuando el pager está ruidoso y tu paciencia silenciosa.

Primero: identifica quién lo dijo

  1. Revisa journald para la línea de error exacta y el nombre del proceso. No adivines.
  2. Confirma si es EMFILE (por proceso) o ENFILE (a nivel sistema). Cambia la solución.

Segundo: comprueba el uso de descriptores en el proceso sospechoso

  1. Obtén PID(s) del demonio sospechoso o del proceso QEMU.
  2. Cuenta los fds abiertos y compáralos con el límite del proceso (desde /proc/<pid>/limits).

Tercero: decide qué aumentar (y dónde)

  1. Si el límite del proceso es bajo y el uso es legítimamente alto, aumenta LimitNOFILE para esa unidad systemd (mejor opción).
  2. Si la tabla de archivos a nivel sistema está agotada, eleva fs.file-max e investiga por qué el sistema acapara manejadores (a menudo una fuga, servicios desbocados o Ceph a escala).
  3. Si es un pico puntual por un job de backup o una restauración, considera reprogramar/limitar la concurrencia y arreglar el patrón de carga en lugar de sólo subir límites.

Una cita que ha resultado dolorosamente cierta en operaciones: (idea parafraseada) “La esperanza no es una estrategia.” — atribuida comúnmente en círculos de liderazgo técnico. Para este error, la esperanza parece “subir todo y reiniciar”. La estrategia es instrumentar y aplicar límites dirigidos.

Datos interesantes y contexto histórico (por qué sigue ocurriendo)

  • Dato 1: Los primeros sistemas Unix solían tener límites por proceso muy pequeños (a veces unas pocas docenas). Los sistemas modernos por defecto usan 1024 o más, pero los valores por defecto siguen reflejando supuestos “de propósito general”, no hosts de virtualización.
  • Dato 2: La separación soft/hard existe para que los procesos puedan aumentar su soft hasta un tope hard. systemd puede establecer ambos.
  • Dato 3: “Todo es un archivo” incluye sockets; un proxy API muy solicitado puede consumir miles de fds sin tocar el disco.
  • Dato 4: QEMU usa múltiples descriptores por disco, por NIC, por hilo vhost, además de eventfds. Una sola VM puede consumir cientos o miles de fds en un host ocupado.
  • Dato 5: inotify usa descriptores y watchers; algunos stacks de monitorización y agentes de logs escalan los watchers agresivamente y pueden alcanzar límites de forma sorprendente.
  • Dato 6: systemd introdujo una forma más explícita, a nivel de unidad, para gestionar límites (LimitNOFILE), reduciendo la dependencia de hacks de ulimit en shells que nunca se aplicaban a demonios.
  • Dato 7: La contabilidad global de manejadores de archivo en Linux ha mejorado, pero aún puedes agotar las tablas de archivos si ejecutas suficientes servicios o filtras fds con el tiempo.
  • Dato 8: Ceph históricamente tiende a necesitar límites de fds más altos; los OSDs pueden requerir un gran número de archivos y sockets abiertos bajo carga.

Chiste #1: Los descriptores de archivo son como salas de reuniones — si nadie se va, al final el edificio “se queda sin” y la gerencia culpa al calendario.

Dónde ocurre en Proxmox: qué servicio suele ser culpable

En un nodo Proxmox, la frase “too many open files” puede aparecer desde múltiples capas. Tu trabajo es dejar de tratar a Proxmox como un monolito y empezar a tratarlo como lo que es: Debian más systemd más una pila de demonios más cargas de trabajo (VMs/CTs) haciendo cosas caóticas.

Demonios de Proxmox (común en clusters ocupados)

  • pveproxy: interfaz web y API. Puede consumir fds por muchas conexiones HTTPS concurrentes, sesiones de navegador de larga duración, configuraciones de proxy inverso y backends de autenticación.
  • pvedaemon: tareas en segundo plano y ayudante de API. Involucrado frecuentemente durante backups, restores, migraciones y escaneos de almacenamiento.
  • pvestatd: recoge estadísticas; puede estresar consultas de almacenamiento y conexiones de red en clusters grandes.
  • pve-cluster / pmxcfs: demonio del sistema de archivos del cluster; los problemas aquí suelen aparecer como comportamiento de cluster extraño, no sólo una línea clara de EMFILE.

Procesos QEMU/KVM (común cuando “una VM se descontrola”)

Si una VM ejecuta una carga con muchas conexiones (proxies, brokers de mensajes, websockets, gateways NAT), puede forzar al proceso QEMU del host a abrir muchos fds para vhost-net, dispositivos tap e interacciones io_uring/eventfd. Si el límite del proceso QEMU es bajo, verás fallos en red, IO de disco o hotplug de dispositivos.

Capas de almacenamiento (ZFS, Ceph, PBS)

  • ZFS normalmente no es la fuente directa de EMFILE en el host, pero los helpers en espacio de usuario y los procesos de backup que interactúan con muchos archivos sí pueden serlo. Piensa en: pipelines de zfs send e indexado de backups.
  • Ceph: los OSDs y monitores son notorios por necesitar límites altos de fds en despliegues reales. “Too many open files” aquí no es exótico; es una comprobación de configuración que deberías hacer temprano.
  • Proxmox Backup Server (si está co-ubicado o integrado): los jobs de backup abren muchos chunks, índices y conexiones. Un límite bajo de fds puede convertir una ventana de backup en un fallo en cámara lenta.

Contenedores (LXC)

Los contenedores LXC pueden alcanzar sus propios límites nofile dentro del namespace del contenedor. Pero no asumas que el contenedor tiene la culpa; el demonio del host que los gestiona puede ser el que se queja. Siempre vincula el error a un PID y luego a una unidad.

Tareas prácticas (comandos, salidas, decisiones) — la lista de verificación operativa

Quieres tareas reales que reduzcan la incertidumbre. Aquí tienes más de una docena. Ejecútalas en orden hasta que tengas un cuello de botella nombrado y un cambio justificado.

Tarea 1: Encuentra la línea de error exacta y el servicio emisor

cr0x@server:~$ journalctl -p err -S -2h | grep -iE "too many open files|EMFILE|ENFILE" | tail -n 20
Dec 26 09:31:12 pve1 pveproxy[1432]: error: accept4: Too many open files
Dec 26 09:31:12 pve1 pveproxy[1432]: failed to accept connection: EMFILE

Qué significa: Esto es un EMFILE de pveproxy PID 1432. No toques aún los globales del kernel; es por proceso.

Decisión: Inspecciona los límites y el recuento de fds del PID 1432. Prepara un override de systemd para pveproxy.service si hace falta.

Tarea 2: Confirma si el sistema está cerca de agotar manejadores globales

cr0x@server:~$ cat /proc/sys/fs/file-nr
23872	0	9223372036854775807

Qué significa: El primer número son manejadores asignados; el tercero es el máximo del sistema. En muchos kernels modernos, el máximo es efectivamente enorme (o dinámico). Si el primer número está cerca del máximo, tienes un problema a nivel sistema.

Decisión: Aquí no está cerca. Enfócate en límites por proceso.

Tarea 3: Comprueba el límite de fds del proceso y el uso actual

cr0x@server:~$ pid=1432; echo "FDs:"; ls -1 /proc/$pid/fd | wc -l; echo; echo "Limits:"; grep -i "open files" /proc/$pid/limits
FDs:
1024

Limits:
Max open files            1024                 1048576              files

Qué significa: El proceso está exactamente en su límite soft (1024). El límite hard es mayor, así que el servicio podría teóricamente aumentarlo, pero no lo hizo.

Decisión: Aumenta LimitNOFILE para la unidad de systemd de forma que systemd lo inicie con un soft mayor. Apunta a algo sensato (por ejemplo, 8192–65536 según la concurrencia).

Tarea 4: Identifica la unidad systemd que corresponde al PID

cr0x@server:~$ systemctl status pveproxy --no-pager
● pveproxy.service - PVE API Proxy Server
     Loaded: loaded (/lib/systemd/system/pveproxy.service; enabled)
     Active: active (running) since Thu 2025-12-26 08:11:02 UTC; 1h 25min ago
   Main PID: 1432 (pveproxy)
      Tasks: 10 (limit: 154675)
     Memory: 76.4M
        CPU: 1min 52.123s

Qué significa: Es una unidad normal, no un proceso misterioso. Bien: podemos sobrescribirla limpiamente.

Decisión: Usa systemctl edit pveproxy para establecer LimitNOFILE. No edites los archivos en /lib/systemd/system directamente.

Tarea 5: Inspecciona límites a nivel de unidad actuales (si existen)

cr0x@server:~$ systemctl show pveproxy -p LimitNOFILE
LimitNOFILE=1024:1048576

Qué significa: systemd lo inició con soft=1024, hard=1048576.

Decisión: Haz un override para un soft mayor (y opcionalmente hard). Si sólo necesitas soft mayor, establece un único valor; systemd acepta LimitNOFILE=65536 (aplica a ambos) o LimitNOFILE=65536:65536.

Tarea 6: Crea un override de systemd para el servicio Proxmox específico

cr0x@server:~$ sudo systemctl edit pveproxy
# (editor opens)

Pon esto en el drop-in:

cr0x@server:~$ cat /etc/systemd/system/pveproxy.service.d/override.conf
[Service]
LimitNOFILE=65536

Qué significa: En el próximo reinicio, pveproxy tendrá un límite de 65k fds. Es suficiente para la mayoría de clusters sin ser un exceso extremo.

Decisión: Recarga systemd y reinicia el servicio. Si esto es el proxy API y estás en medio de una caída, hazlo en una ventana segura o desde la consola del nodo.

Tarea 7: Aplica y verifica que los nuevos límites se han aplicado realmente

cr0x@server:~$ sudo systemctl daemon-reload
cr0x@server:~$ sudo systemctl restart pveproxy
cr0x@server:~$ systemctl show pveproxy -p LimitNOFILE
LimitNOFILE=65536:65536

Qué significa: La unidad ahora está configurada correctamente.

Decisión: Confirma que el PID en ejecución tiene el nuevo límite, no sólo los metadatos de la unidad.

Tarea 8: Confirma el límite efectivo del PID en ejecución

cr0x@server:~$ pid=$(pidof pveproxy); grep -i "open files" /proc/$pid/limits
Max open files            65536                65536                files

Qué significa: El proceso se está ejecutando efectivamente con el nuevo límite. Ese es el punto.

Decisión: Vigila si reaparece. Si el uso de fds sigue subiendo, puede haber una fuga o una sobrecarga upstream.

Tarea 9: Ver qué tipo de fds se están consumiendo (sockets vs archivos)

cr0x@server:~$ pid=$(pidof pveproxy); sudo ls -l /proc/$pid/fd | awk '{print $11}' | head
socket:[942113]
socket:[942115]
/dev/null
socket:[942118]
anon_inode:[eventfd]

Qué significa: Si la lista es mayormente socket:, estás tratando con concurrencia de conexiones. Si son rutas reales, puedes estar escaneando muchos archivos o atascado en almacenamiento.

Decisión: Si son sockets, considera proxies frontales, keepalives, backends de autenticación y comportamiento del cliente. Si son rutas de filesystem, investiga qué las abre y por qué.

Tarea 10: Identifica los mayores consumidores de fds en el nodo (triage rápido)

cr0x@server:~$ for p in /proc/[0-9]*; do
  pid=${p#/proc/}
  comm=$(tr -d '\0' < $p/comm 2>/dev/null) || continue
  fdc=$(ls -1 $p/fd 2>/dev/null | wc -l)
  echo "$fdc $pid $comm"
done | sort -nr | head -n 10
18034 28741 ceph-osd
 9123 1942 qemu-system-x86
 5012 1432 pveproxy
 2120 1567 pvedaemon

Qué significa: Tienes a los villanos ordenados por recuento de fds.

Decisión: Si un OSD de Ceph domina, tal vez necesites ajustar límites de systemd de Ceph también. Si QEMU es grande, enfócate en la VM concreta y su método de arranque.

Tarea 11: Para QEMU: mapa un PID QEMU a un VMID

cr0x@server:~$ pid=1942; tr '\0' ' ' < /proc/$pid/cmdline | sed -n 's/.*-id \([0-9]\+\).*/VMID=\1/p'
VMID=104

Qué significa: Ese proceso QEMU es la VM 104.

Decisión: Comprueba si está subiendo repetidamente el uso de fds durante backups, alta carga de conexiones o una mala configuración de dispositivos.

Tarea 12: Comprueba el límite del proceso QEMU y si es demasiado bajo

cr0x@server:~$ pid=1942; grep -i "open files" /proc/$pid/limits
Max open files            4096                 4096                 files

Qué significa: QEMU está limitado a 4096. Eso puede ser aceptable, o totalmente insuficiente para una VM gateway ocupada.

Decisión: Si QEMU falla con EMFILE y el uso se acerca a 4096, aumenta el límite para el scope/servicio que inicia VMs (ver la sección “Aumentar límites correctamente”).

Tarea 13: Encuentra la unidad/scope de systemd para un PID QEMU

cr0x@server:~$ pid=1942; systemctl status $pid --no-pager
● 104.scope - qemu-kvm -id 104
     Loaded: loaded
     Active: active (running) since Thu 2025-12-26 08:22:51 UTC; 1h 13min ago
   Main PID: 1942 (qemu-system-x86)

Qué significa: La VM se ejecuta en un scope de systemd nombrado por VMID. Los límites pueden provenir del servicio padre o de los valores por defecto de systemd.

Decisión: Ajustar scopes por VM es posible pero generalmente no es el mejor modelo operativo. Prefiere arreglar la unidad/plantilla que lanza QEMU (a menudo vía herramientas de Proxmox), o usar los defaults del gestor systemd si procede.

Tarea 14: Comprueba límites por defecto de systemd (a veces el culpable oculto)

cr0x@server:~$ systemctl show --property DefaultLimitNOFILE
DefaultLimitNOFILE=1024:524288

Qué significa: Los valores por defecto de systemd pueden influir en scopes y servicios que no establecen sus propios límites explícitamente.

Decisión: No lo aumentes a la ligera. Es una perilla de “radio de impacto”. Úsalo sólo si muchos servicios no relacionados necesitan límites más altos y has validado el impacto en memoria y monitorización.

Tarea 15: Comprueba límites por usuario (útil para herramientas interactivas y sesiones PAM)

cr0x@server:~$ ulimit -n
1024

Qué significa: Tu sesión shell tiene límite 1024. Esto no se aplica automáticamente a servicios systemd.

Decisión: Si tus herramientas operativas (scripts personalizados, jobs rsync, flujos de backup CLI) alcanzan EMFILE en sesiones interactivas, ajusta límites de PAM. De lo contrario, prioriza overrides de systemd.

Tarea 16: Si sospechas una fuga, vigila el recuento de fds a lo largo del tiempo

cr0x@server:~$ pid=$(pidof pvedaemon); for i in $(seq 1 10); do date; ls -1 /proc/$pid/fd | wc -l; sleep 30; done
Thu Dec 26 09:40:01 UTC 2025
812
Thu Dec 26 09:40:31 UTC 2025
829
Thu Dec 26 09:41:01 UTC 2025
846

Qué significa: Si sólo sube y nunca baja bajo carga estable, algo puede estar filtrando fds (o tienes un número creciente de conexiones de larga vida).

Decisión: Aumentar límites puede comprar tiempo, pero debes perseguir la fuga: logs, actualizaciones recientes, plugins, backends de auth o un balanceador que haga cosas “creativas”.

Tarea 17: Identifica qué peers remotos mantienen sockets abiertos (para proxies)

cr0x@server:~$ pid=$(pidof pveproxy); sudo lsof -nP -p $pid | awk '/TCP/ {print $9}' | head
10.20.5.18:8006->10.20.5.40:51522
10.20.5.18:8006->10.20.7.91:50944

Qué significa: Puedes ver IPs y puertos de clientes. Si un cliente abre un número ridículo de conexiones, encontraste un problema de comportamiento.

Decisión: Arregla el cliente, añade un proxy con límites sensatos o ajusta keepalives. Subir límites sin abordar clientes abusivos es como comprar un contenedor de basura más grande para un mapache.

Aumentar límites correctamente: kernel vs systemd vs app

Empieza por la solución más quirúrgica

Si un servicio específico alcanza EMFILE, establece LimitNOFILE para ese servicio. Es el enfoque más limpio: medible, reversible y de colateral mínimo.

Override de systemd: el movimiento por defecto para servicios Proxmox

Los demonios de Proxmox son unidades systemd. Cambias límites con drop-ins en /etc/systemd/system/<unit>.service.d/override.conf. Ese archivo sobrevive actualizaciones y le dice a tu yo futuro qué hiciste.

Unidades comunes de Proxmox a considerar:

  • pveproxy.service (UI/API)
  • pvedaemon.service (tareas, ayudante de API)
  • pvestatd.service (estadísticas)
  • pve-cluster.service (sistema de archivos del cluster)
  • ceph-osd@<id>.service, ceph-mon@<name>.service (si ejecutas Ceph en el nodo)

¿Cuánto debería poner en LimitNOFILE?

Elige números que correspondan a la realidad operativa:

  • 8192: buen aumento para demonios ligeros que ocasionalmente hacen picos.
  • 16384–65536: común para proxies ocupados, demonios de gestión en clusters grandes y procesos relacionados con backups.
  • 131072+: reservado para los pesados (OSDs de Ceph a escala, servicios de red de alto rendimiento). No lo pongas sólo porque lo viste en un foro.

El límite no es gratis: cada fd consume recursos del kernel. En sistemas modernos esto suele ser aceptable, pero “aceptable” depende de la presión de memoria, número de procesos y cuántos fds usan realmente.

Cuándo importan los límites globales del kernel

Agotamiento global de manejadores de archivo es más raro, pero ocurre en:

  • nodos que ejecutan muchos servicios (monitorización, envío de logs, almacenamiento, proxies inversos)
  • nodos con carga Ceph intensa
  • sistemas con fugas de fds en múltiples procesos

Inspecciona la configuración actual:

cr0x@server:~$ sysctl fs.file-max
fs.file-max = 9223372036854775807

En muchos kernels modernos, este valor es enorme o efectivamente ilimitado. En ese caso, ENFILE es menos probable y EMFILE sigue siendo el problema principal. Aun así, no asumas; mide.

Límites por usuario: útiles, pero no tu palanca principal para demonios Proxmox

/etc/security/limits.conf y ulimit -n importan para sesiones de usuario, cron y scripts ejecutados por humanos. No controlan de forma fiable servicios gestionados por systemd (systemd establece rlimits por sí mismo). Si “arreglaste” un demonio Proxmox editando limits.conf, tuviste suerte o cambiaste otra cosa al mismo tiempo.

Aumentar límites de QEMU: qué debes y no debes hacer

Si QEMU alcanza límites de fds, tienes dos preguntas en paralelo:

  1. ¿La carga de la VM es legítimamente intensiva en fds (muchas conexiones/dispositivos)?
  2. ¿Los procesos QEMU se inician con un rlimit sensato para tu entorno?

Aumentar límites de QEMU puede hacerse ajustando el entorno de systemd que los lanza (según tu versión de Proxmox y cómo se scopean las VMs). En la práctica, recomiendo:

  • Primero, confirma que el PID QEMU alcanza el límite (no el SO invitado).
  • Luego, considera elevar el default del servicio spawner solo si varias VMs muestran el mismo problema.
  • Para una VM fuera de rango, considera soluciones a nivel de carga: pooling de conexiones, reducir keepalives agresivos, arreglar fugas en la aplicación o dividir roles entre VMs.

Chiste #2: “Simplemente pondremos LimitNOFILE a infinito” es como aprendes qué significa “memoria finita” en producción.

Tres mini-historias corporativas desde el frente

Mini-historia 1: El incidente causado por una suposición equivocada

Gestionaban un cluster Proxmox de tamaño medio para servicios internos y algunas aplicaciones orientadas a clientes. Una mañana, la UI web empezó a colgarse. Luego fallaron las llamadas API. Luego los backups se pusieron en cola. El equipo asumió que el nodo estaba “caído” en el sentido clásico: CPU saturada, disco lleno, red muerta. Nada de eso era cierto.

La pista estaba en journald: pveproxy no podía aceptar nuevas conexiones. “Too many open files.” Alguien había puesto recientemente un dashboard interno en modo kiosco en una pantalla de pared. Se actualizaba agresivamente, abría múltiples conexiones API paralelas y nunca las cerraba correctamente. Multiplica eso por unas cuantas TVs y unos cuantos desarrolladores con pestañas abiertas por días, y obtienes una denegación de servicio en cámara lenta.

La suposición equivocada fue creer que “too many open files” debía significar “ZFS abrió demasiados archivos” o “el almacenamiento está roto”. Pasaron horas persiguiendo salud de pools y datos SMART. Mientras tanto, el proxy estaba en 1024 fds y rechazaba la misma UI que necesitaban para depurar.

La solución fue simple: aumentar LimitNOFILE para pveproxy a un valor sensato y arreglar el cliente ofensivo. La lección fue más valiosa: siempre vincula el error a un PID, luego a una unidad y luego a una carga. Adivinar sale caro.

Mini-historia 2: La optimización que salió mal

Otra organización quería backups más rápidos. Ajustaron la programación para ejecutar más jobs en paralelo y acortaron ventanas de retención. En papel tenía sentido: más concurrencia, más rendimiento, menos tiempo en ventana. También desplegaron monitorización adicional que tail-aba muchos logs y vigilaba muchos directorios.

Luego los backups empezaron a fallar de forma intermitente. A veces era el proceso de backup. A veces un demonio de gestión. A veces un servicio aparentemente no relacionado como un colector de métricas. El patrón era “aleatorio”, que es lo que llamas un límite de recurso sistémico cuando aún no lo has admitido.

El contragolpe fue que cada worker de backup paralelo y cada agente de monitorización multiplicaron el uso de fds. Individualmente, cada servicio parecía estar bien. Colectivamente, el nodo pasó largos periodos con muchos procesos cerca de sus caps soft. Picos ocasionales empujaron a uno de ellos por encima del límite y el que tuvo mala suerte arrojó EMFILE primero.

Lo “arreglaron” una vez subiendo un default global y siguieron. Un mes después el mismo patrón volvió, excepto que ahora el nodo tenía también mayor presión de memoria y más procesos. La solución correcta y aburrida fue: establecer LimitNOFILE explícito para los servicios pesados conocidos, reducir la paralelidad de backups para ajustarla al backend de almacenamiento y medir el uso de fds durante picos. El rendimiento mejoró, los fallos pararon y no tuvieron que seguir subiendo techos eternamente.

Mini-historia 3: La práctica aburrida pero correcta que salvó el día

Un equipo que corría Ceph en Proxmox tenía la costumbre que parecía poco cool: mantenían un runbook con tres comprobaciones simples para cualquier error de plataforma. Una de esas comprobaciones era “uso de fds vs límites”. También versionaban los drop-ins de systemd para servicios críticos (no los archivos gestionados por Proxmox, sino los overrides en /etc).

Durante una expansión de almacenamiento, un nuevo despliegue de OSDs empezó a flaquear. Los síntomas parecían de red: heartbeats perdidos, operaciones lentas, reinicios ocasionales de demonios. Pero el runbook les obligó a revisar lo básico. Los procesos OSD estaban alcanzando su límite de fds bajo el nuevo patrón de carga y layout.

Como ya tenían una política conocida para límites de unidades Ceph, la solución no fue una búsqueda frenética en foros. Aplicaron el patrón de override existente, reiniciaron los servicios afectados en una secuencia controlada y validaron con un solo comando que límites y uso ahora tenían margen.

El día lo salvaron cosas aburridas: comprobaciones repetibles e higiene de configuración. Nada heroico. Ningún “simplemente reinícelo”. El cluster siguió sirviendo IO y la ventana de cambio acabó a tiempo. En operaciones, lo aburrido es una característica.

Errores comunes: síntoma → causa raíz → solución

Error 1: “Aumenté ulimit -n y sigue fallando”

Síntoma: Ejecutas ulimit -n 65535 en tu shell, reinicias un servicio Proxmox y aún ves EMFILE.

Causa raíz: Los servicios systemd no heredan el ulimit de tu shell. systemd establece rlimits por sí mismo.

Solución: Establece LimitNOFILE en un drop-in systemd para la unidad específica, luego reinicia la unidad y verifica en /proc/<pid>/limits.

Error 2: Aumentar el default global de systemd porque un servicio se portó mal

Síntoma: Cambias DefaultLimitNOFILE a nivel sistema y todo parece bien… hasta que servicios no relacionados empiezan a consumir más recursos.

Causa raíz: Expandiste el radio de impacto. Ahora muchos servicios pueden abrir más fds, lo que puede amplificar fugas y aumentar la presión de memoria del kernel.

Solución: Mantén los defaults conservadores. Aumenta límites sólo en unidades que lo necesiten. Usa el default solo después de confirmar que muchos servicios comparten el mismo requerimiento legítimo.

Error 3: Tratar EMFILE como un “problema de almacenamiento”

Síntoma: Un backup falla con “too many open files” y el equipo se zambulle en tuning de ZFS.

Causa raíz: El proceso que falla suele ser un demonio o worker de backup que abre muchos ficheros/sockets, no ZFS en sí.

Solución: Identifica el PID emisor y comprueba su límite y recuento de fds. Luego aumenta el límite de esa unidad o reduce concurrencia.

Error 4: Aumentar límites sin comprobar fugas

Síntoma: El nodo funciona durante una semana tras subir límites y luego colapsa otra vez.

Causa raíz: Una fuga real (fds nunca liberados) o comportamiento de conexión desbocado; un límite mayor sólo retrasó el fallo.

Solución: Toma series temporales del recuento de fds para procesos sospechosos. Si el crecimiento es monótono, trátalo como bug o problema de carga. Escala al proveedor/comunidad con evidencia (crecimiento de fds, muestras de lsof, líneas de journald).

Error 5: Confundir límites del huésped con límites del host

Síntoma: Una app en un contenedor lanza EMFILE, así que aumentas límites en el host y nada cambia.

Causa raíz: El límite está dentro del contenedor o del runtime de la app, no en el proceso del host.

Solución: Comprueba dentro del contenedor (ulimit -n) y comprueba también el proceso del host. Arregla la capa que falla realmente.

Error 6: Reiniciar servicios al azar hasta que el error desaparece

Síntoma: Tras reinicios, “vuelve a funcionar”, pero nadie sabe por qué.

Causa raíz: Reiniciar cierra fds abiertos, enmascarando temporalmente la carga o las fugas.

Solución: Usa reinicios como estabilización, no como diagnóstico. Antes de reiniciar, captura: el error en journald, PID, límites, recuento de fds y una muestra de lsof.

Listas de verificación / plan paso a paso (secuencia segura de cambios)

Checklist A: Viste “too many open files” en UI/API de Proxmox

  1. Extrae errores de journald de las últimas 1–2 horas; encuentra el binario emisor y el PID.
  2. Comprueba si es EMFILE vs ENFILE.
  3. Cuenta fds abiertos para el PID y compáralo con /proc/<pid>/limits.
  4. Si el recuento está cerca del límite: establece LimitNOFILE para la unidad específica y reiníciala.
  5. Si el recuento está muy por debajo del límite: puede ser un pico transitorio; investiga concurrencia, comportamiento de clientes y logs alrededor de la marca temporal.
  6. Tras el cambio, verifica límites nuevos en el PID en ejecución y monitoriza recurrencia.

Checklist B: Sospechas que procesos QEMU alcanzan límites

  1. Encuentra el PID QEMU desde el mensaje de error o desde los consumidores top de fds.
  2. Mapea PID a VMID usando la cmdline (-id).
  3. Comprueba /proc/<pid>/limits y recuento de fds. Si está cerca: es real.
  4. Decide: arreglar el patrón de carga (preferible para una sola VM) vs aumentar límites (si afectan muchas VMs).
  5. Tras cambios, valida ejecutando la misma carga y observando margen de fds.

Checklist C: Ejecutas Ceph en Proxmox y ves EMFILE

  1. Identifica qué demonio Ceph (OSD/MON/MGR) registró EMFILE.
  2. Revisa el límite de unidad systemd de ese demonio y el límite del PID en ejecución.
  3. Aplica override de unidad para ese tipo de demonio (a menudo unidades plantilladas como ceph-osd@.service).
  4. Reinicia en orden controlado, vigilando la salud del cluster.
  5. Confirma uso de fds bajo carga y asegúrate de no haber postergado una fuga.

Paso a paso: la forma “correcta” de aumentar un límite para un demonio Proxmox

  1. Mide límite y uso actuales (/proc/<pid>/limits y recuento de /proc/<pid>/fd).
  2. Elige un valor nuevo con margen (usualmente 8–64x del pico actual, no 1000x).
  3. Crea un drop-in systemd con systemctl edit <unit>.
  4. systemctl daemon-reload.
  5. Reinicia la unidad en una ventana apropiada.
  6. Verifica con systemctl show y /proc/<pid>/limits.
  7. Monitoriza: recuento de fds en el tiempo, logs de errores y comportamiento de clientes.
  8. Escribe por qué lo hiciste. Tu yo futuro es una persona distinta con menos contexto y más cafeína.

Preguntas frecuentes (FAQ)

1) ¿Debo aumentar fs.file-max para arreglar “too many open files” en Proxmox?

Normalmente no. La mayoría de incidentes en Proxmox son EMFILE por proceso. Aumenta primero el LimitNOFILE del servicio. Toca los globales del kernel sólo si puedes demostrar agotamiento global.

2) ¿Cuál es un buen LimitNOFILE por defecto para pveproxy?

Para instalaciones pequeñas, 8192 suele ser suficiente. Para clusters muy concurridos con muchos clientes UI/API o automatización, 65536 es un techo pragmático. Si necesitas más, probablemente también tengas que arreglar comportamiento de clientes.

3) ¿Por qué ulimit -n muestra 1024 aunque puse límites más altos en systemd?

ulimit -n refleja tu sesión de shell actual. Los servicios systemd tienen sus propios rlimits. Comprueba el PID del servicio en /proc/<pid>/limits para ver qué vale realmente.

4) ¿Aumentar nofile puede causar inestabilidad?

Indirectamente, sí. Límites más altos permiten a procesos asignar más recursos del kernel. Si además tienes fugas, sólo diste más margen a la fuga. Usa límites más altos con monitorización y series temporales de fds.

5) Mi contenedor dice “too many open files”. ¿Debo cambiar el host?

Quizá, pero empieza dentro del contenedor: comprueba el límite de la app y el límite del contenedor. Si el proceso host LXC/QEMU es el que alcanza EMFILE, entonces ajusta en el host la unidad o el scope correspondiente.

6) ¿Cómo sé si es una fuga o concurrencia legítima?

Las fugas muestran recuentos de fds que suben de forma sostenida y no bajan, incluso cuando la carga cae. La concurrencia legítima suele seguir patrones de tráfico. Toma muestras temporales del recuento de fds e inspecciona tipos de fd (sockets vs archivos).

7) ¿Qué servicios Proxmox son más sensibles a límites de fds?

pveproxy y pvedaemon son comunes. En clusters grandes, pvestatd y componentes de cluster pueden mostrar problemas. Con Ceph, los demonios Ceph son candidatos frecuentes.

8) Aumenté límites pero aún veo errores. ¿Ahora qué?

Confirma que el PID en ejecución tiene el nuevo límite (no confíes en archivos de config). Luego comprueba si el uso de fds alcanza el nuevo tope. Si lo hace, necesitas un límite mayor o tienes un runaway real. Si no lo hace, el error puede venir de un proceso diferente al que crees.

9) ¿Hay un número “one size fits all” para nodos Proxmox?

No, y esa es la trampa. Los nodos de virtualización alojan cargas muy distintas. Fija límites por servicio basados en picos medidos y concurrencia esperada, no en superstición.

Conclusión: pasos prácticos siguientes

Si recuerdas una cosa: “too many open files” no es una sensación. Es un techo de recurso medible. Tu primer trabajo es la atribución: qué PID, qué unidad, qué límite. Tu segundo trabajo es elegir el cambio más pequeño y efectivo: un override systemd LimitNOFILE para el servicio específico que realmente alcanzó EMFILE. Tu tercer trabajo es asegurarte de que no acabaste de darle a una fuga una mecha más larga.

Pasos siguientes que puedes hacer hoy:

  1. Añade un comando rápido de triage de fds a tu runbook (PID → recuento de fds → límites).
  2. Establece overrides explícitos de LimitNOFILE para servicios Proxmox pesados conocidos en tu entorno (pveproxy, pvedaemon, demonios Ceph si aplica).
  3. Durante operaciones pico (ventanas de backup, migraciones), toma muestras del uso de fds y guarda los números. La evidencia vence a las discusiones.
← Anterior
Despliegues los viernes por la noche: la tradición que enseña a través del dolor
Siguiente →
Docker vs iptables/nftables: detener la guerra de cortafuegos y arreglar las redes

Deja un comentario