Cómo resolver el error 'Too many open files' en Linux en servidores PHP‑FPM durante picos de carga
Por Kevin Marcondes · Publicado el · 8 min de lectura
Cómo resolver el error 'Too many open files' en Linux en servidores PHP‑FPM durante picos de carga: comprende qué agota los descriptores de archivo (FDs), cómo diagnosticar en producción y qué ajustes aplicar por capa (systemd, kernel, FPM y Nginx). A continuación verás pasos prácticos para estabilizar sin falsas promesas.
Síntomas reales y cuándo aparece el error
Ocurre en picos de tráfico, cuando PHP‑FPM acepta nuevas conexiones mientras mantiene FDs abiertos: sockets, logs, archivos temporales y conexiones a upstreams. Los síntomas incluyen 502/504 en Nginx, fallos intermitentes en APIs y mensajes de error en los logs del FPM y del servidor web.
No lo confundas con agotamiento de puertos efímeros. Aquí el problema es el techo de descriptores de archivo del proceso, del servicio o del kernel.
- 502/504 y caídas momentáneas bajo carga.
- Mensajes 'Too many open files' en los logs de PHP‑FPM.
- Aumento de latencia y colas en el servidor web.
- Conexiones a base de datos y caches fallando por falta de FDs.
Diagnóstico inmediato en producción (sin pánico)
Haz tres comprobaciones: 1) confirma el error en el log; 2) revisa el límite efectivo de FDs del master del FPM; 3) cuenta FDs abiertos para entender la brecha. Esto orienta el ajuste correcto por capa. Si ya expones métricas, correlaciona colas del FPM con el uso de FDs — por ejemplo, exponer métricas de PHP‑FPM.
# 1) Confirme no log do FPM
sudo grep -i "too many open files" /var/log/php*-fpm*.log || true
# 2) Descubra o PID do master do PHP-FPM
pgrep -x "php-fpm" || pgrep -x "php-fpm8.2" || pgrep -x "php-fpm7.4"
PID=<<coloque_o_pid_aqui>>
# Limites efetivos do processo (procfs)
cat /proc/$PID/limits | grep -i "open files"
# Também veja o LimitNOFILE do unit systemd correspondente
systemctl show php-fpm --property=LimitNOFILE 2>/dev/null || \
systemctl show php8.2-fpm --property=LimitNOFILE 2>/dev/null
# 3) Quantos FDs o master mantém abertos agora?
lsof -p $PID | wc -l
# Tipos mais comuns de FDs (visão rápida)
lsof -p $PID | awk '{print $5}' | sort | uniq -c | sort -nr | head -n 10
De dónde viene el límite: capas que controlan los FDs
El techo de FDs es la combinación del kernel, el gestor de servicios y la aplicación. Ajustar solo el ulimit del shell no afecta a servicios gestionados por systemd. Entiende la pila antes de cambiar valores.
| Capa | Dónde ajustar | Parámetro principal | Cómo verificar |
|---|---|---|---|
| Kernel (global) | /etc/sysctl.d/*.conf | fs.file-max | sysctl fs.file-max |
| systemd (servicio) | override de la unit | LimitNOFILE | systemctl show <unit> --property=LimitNOFILE |
| PHP-FPM (pool) | www.conf (o el pool correspondiente) | rlimit_files | /proc/$PID/limits (Open files) |
| Nginx (worker) | nginx.conf | worker_rlimit_nofile | nginx -T | grep rlimit |
| Shell/PAM (login) | /etc/security/limits*.conf | nofile | ulimit -n (en sesión interactiva) |
| Contenedores (Docker) | compose.yaml / run | ulimits: nofile | docker inspect ... | jq '.[0].HostConfig.Ulimits' |
Corrección rápida centrada en el servicio (systemd + FPM)
Aumenta el LimitNOFILE en la unit del PHP‑FPM y, opcionalmente, rlimit_files en el pool. Requiere reinicio del servicio, ya que los límites se aplican al crear el proceso. Para reducir impacto al usuario, considera una conmutación de tráfico con el patrón despliegue blue‑green antes del restart.
- Usa un valor con margen para el pico previsto.
- Revisa los logs tras el reinicio para confirmar.
- No superes la capacidad del kernel (fs.file-max).
# 1) Override no systemd
sudo systemctl edit php-fpm || sudo systemctl edit php8.2-fpm
# Adicione no editor que abrir:
# [Service]
# LimitNOFILE=131072
sudo systemctl daemon-reload
sudo systemctl restart php-fpm || sudo systemctl restart php8.2-fpm
# 2) (Opcional) rlimit_files no pool do FPM
# Em /etc/php/*/fpm/pool.d/www.conf ou similar:
# rlimit_files = 131072
# Depois, reinicie o PHP-FPM novamente.
# Valide
systemctl show php-fpm --property=LimitNOFILE 2>/dev/null || \
systemctl show php8.2-fpm --property=LimitNOFILE 2>/dev/null
cat /proc/$(pgrep -x php-fpm | head -n1)/limits | grep -i "open files"
Ajustes persistentes y dimensionamiento seguro
Asegura que el kernel y el servicio soporten el nuevo techo. Ajusta fs.file-max y revisa parámetros del pool del FPM para evitar un crecimiento descontrolado. Evita aumentar límites sin monitorizar CPU, memoria e I/O, porque puedes trasladar el cuello de botella.
- Kernel: aumenta fs.file-max de forma persistente.
- FPM: revisa pm.max_children y pm.process_idle_timeout.
- Logs: una rotación adecuada evita exceso de FDs abiertos.
# Kernel: persistir um teto global mais alto
echo 'fs.file-max = 1000000' | sudo tee /etc/sysctl.d/99-fd.conf
sudo sysctl --system
# PHP-FPM (pool): além de rlimit_files, confira a capacidade de workers
# Ex.: pm = dynamic; pm.max_children = <valor_compatível_com_recursos>
# Consulte a documentação oficial do PHP-FPM para detalhes dos parâmetros.
Nginx, conexiones e interacción con contenedores (Docker)
Si Nginx hace proxy al FPM, los workers también necesitan un techo mayor. En contenedores, establece ulimits por servicio. Ten en cuenta que los límites del contenedor no heredan del host por defecto. Si estás decidiendo el proxy inverso, revisa criterios en Traefik vs Nginx.
- Nginx: ajusta worker_rlimit_nofile y worker_connections.
- Docker: define ulimits:nofile en el compose o al ejecutar containers.
- Orquestadores aplican límites propios; revisa los manifests.
# docker-compose.yml (exemplo)
services:
php-fpm:
image: php:8.2-fpm
ulimits:
nofile:
soft: 131072
hard: 131072
nginx:
image: nginx:stable
ulimits:
nofile:
soft: 131072
hard: 131072
Prevención: métricas, logs y pruebas de carga
Estabiliza la operación con visibilidad y ensayos de pico. Mide FDs y colas del FPM, centraliza logs y prueba cambios antes del horario crítico. Combina alertas de FDs altos con gráficos de tráfico para anticipar la saturación.
- Métricas y visualización: configura Prometheus y Grafana.
- Logs estructurados y correlación bajo carga: logs JSON y correlación.
- Conmutación sin downtime al reiniciar servicios: patrón despliegue blue‑green.
- Contenedores: combina ulimits con cgroups. Guía: cgroup v2 + systemd.
Checklist de verificación post‑corrección
Confirma que los nuevos límites están activos y que la aplicación soporta el pico simulado. No ejecutes pruebas de carga en producción sin control. Usa ventana de mantenimiento, límites y monitorización en tiempo real.
- LimitNOFILE de la unit está correcto.
- /proc/$PID/limits refleja el nuevo techo.
- lsof bajo carga permanece por debajo del límite.
- Nginx y contenedores también ajustados.
- Logs sin nuevos 'Too many open files'.
systemctl show php-fpm --property=LimitNOFILE 2>/dev/null || \
systemctl show php8.2-fpm --property=LimitNOFILE 2>/dev/null
PID=$(pgrep -x php-fpm | head -n1)
cat /proc/$PID/limits | grep -i "open files"
# Simule carga leve e observe:
watch -n2 "lsof -p $PID | wc -l"
Preguntas frecuentes
¿Qué causa 'Too many open files' en PHP‑FPM?
El proceso alcanzó el techo de descriptores de archivo. Esto incluye sockets, archivos de log y temporales. En picos, cada worker mantiene múltiples FDs, que se suman a los límites del servicio (LimitNOFILE), del pool (rlimit_files) y del kernel (fs.file-max).
¿Es suficiente aumentar el ulimit en el shell para resolverlo?
No. Los servicios gestionados por systemd ignoran el ulimit de tu sesión interactiva. Debes ajustar LimitNOFILE en la unit del servicio y, opcionalmente, rlimit_files en el pool del PHP‑FPM, además de garantizar un fs.file-max adecuado en el kernel.
¿Necesito reiniciar PHP‑FPM después de cambiar los límites?
Sí. Límites como LimitNOFILE y rlimit_files se aplican al crear el proceso. Un reload no cambia esos valores. Planifica reiniciar el FPM de forma segura, drenando conexiones vía proxy inverso para evitar errores visibles al usuario.
¿Qué riesgos tiene definir límites demasiado altos?
Si fijas un límite muy alto sin capacidad real (CPU/RAM/I/O), el servidor puede aceptar más trabajo del que soporta y degradarse. Además, el kernel tiene un techo global (fs.file-max). Ajusta con margen razonable y monitoriza para calibrar.
¿Cómo ajustar en entornos con Docker Compose?
Define ulimits:nofile por servicio en el compose o al ejecutar containers. Ajusta Nginx y PHP‑FPM por separado. Ten en cuenta que los límites del host no se aplican automáticamente a los containers. Verifica con docker inspect y monitorea bajo carga.
¿Quieres ayuda para estabilizar tu PHP‑FPM en picos?
Diagnóstico guiado, ajustes de límites por capa y validaciones con observabilidad. Hablemos de tu escenario y de los pasos prácticos siguientes.
Hablar sobre mi entornoVer también
- 502 Bad Gateway intermitente en Docker Compose con Nginx y PHP‑FPM: cómo diagnosticar y corregir timeouts y exceso de conexiones
- Cómo diagnosticar y capturar paquetes por intermitencias de red entre contenedores Docker en Debian
- Cómo detectar y corregir inconsistencias de SKUs duplicados entre WooCommerce y ERP sin perder pedidos
- Cómo reducir el tiempo de recuperación tras un crash de un servidor Linux con playbook Ansible y runbook de recuperación