Nginx muestra "se agotó el tiempo de espera del flujo ascendente al leer el encabezado de respuesta del flujo ascendente". PHP-FPM indica cola de escucha longitud 32. Reflejo inmediato: cambie pm.max_children de 50 a 150. El tráfico se absorbe: la RAM aumenta al 98%, el asesino de OOM ataca a MySQL. Causa nunca abordada: un webhook de pago sincrónico de 25 segundos por pedido.
PHP-FPM saturado presenta dos enfermedades con síntomas similares: realmente no hay suficientes trabajadores para una carga corta de CPU, o trabajadores bloqueados en la E/S de la red, consulta SQL lenta, bloqueo de archivos. Confundir ambos cuesta mucha RAM y oculta el verdadero cuello de botella durante semanas.
Si el registro lento muestra el mismo seguimiento de llamadas en todas partes, no es un problema de FPM, es ese seguimiento de llamadas.
La regla de oro: registro lento de veinticuatro horas, luego ajuste de tarde, nunca al revés. Criar a max_children sin acortar el camino crítico significa contratar cajeros mientras cada cliente todavía paga con cheques sin fondos.
Leer el estado de php-fpm y el registro lento
Primero habilite la visibilidad:
pm.status_path = /fpm-estado
ping.ruta = /fpm-ping
request_slowlog_timeout = 5s
registro lento = /var/log/php-fpm/slow.log
Proteja /fpm-status detrás de nginx; no lo exponga públicamente. Señales de saturación:
procesos activos≈ max permanentemente;cola de escucha> 0;El servidor alcanzó los registros de pm.max_children.
Fórmula de RAM: (max_children × memoria por niño) + OS + MySQL < RAM total - margen mínimo del 20%.
Diagnóstico A vs B: trabajadores insuficientes o código de bloqueo
A — trabajadores insuficientes: solicitudes de menos de 200 ms, procesador PHP alto, registro lento vacío o rastros diversificados → aumentar pm.max_children en pasos de diez, monitoreando la RAM.
B — código de bloqueo: trabajadores activos, procesador bajo, registro lento concentrado en la misma línea (curl, PDO, file_get_contents) → poner en cola asincrónica, tiempo de espera de curl de tres a cinco segundos, corregir el índice SQL; consulte índice MySQL faltante y perfiles PHP.
Alinee fastcgi_read_timeout nginx con la realidad de la aplicación: un tiempo de espera de nginx más corto que el webhook oculta el problema en 504 sin registro lento. En compartido, un límite de proceso impuesto por el host es una señal de actualización de VPS en lugar de un ajuste infinito.
Para consultas N+1, consulte sitio dinámico MySQL: un bucle de consulta puede bloquear a todos los trabajadores sin una CPU elevada.
Tuning pm: dinámico, bajo demanda, estático
| Moda | Cuando usarlo | Riesgo |
|---|---|---|
| dinámico | Tráfico variable, RAM controlada | Picos inesperados si max_children es demasiado bajo |
| bajo demanda | Tráfico esporádico, RAM limitada | Latencia de arranque en frío |
| estático | Carga plana, RAM predecible | Desperdicio si el tráfico es bajo |
Comience con pm = dinámico con pm.max_children calculado en la fórmula RAM. Pruebe "bajo demanda" solo si la latencia de arranque en frío es aceptable para su audiencia.
La cumbre: no más trabajadores con código de bloqueo
Compare VPS donde controla PHP-FPM a través del directorio. En una plataforma compartida, el límite del proceso no es negociable: el diagnóstico sigue siendo el mismo, pero la solución implica una actualización u optimización del código.
Decide y avanza sin puntos ciegos
Antes de aumentar max_children:
- Activar estado y registro lento: sin visibilidad, estás sintonizando a ciegas.
- Clasifique la saturación: procesador alto (A) o procesador bajo de trabajadores ocupados (B).
- Corrija el código o SQL si el registro lento está concentrado; no se debe realizar ningún ajuste pm antes de la corrección.
- Ajuste pm.max_children en incrementos de diez con el presupuesto de RAM documentado.
- Alinear fastcgi_read_timeout nginx y tiempos de espera de aplicaciones (curl, PDO).
- Prueba de carga el mismo punto final después de aplicar el parche: la cola debe permanecer en cero bajo carga normal.
Preguntas frecuentes
¿Cómo sé si PHP-FPM está saturado?
cola de escucha mayor que cero, registros max_children alcanzados, errores nginx 502/504, latencia lineal con el tráfico. Habilite pm.status_path para observar antes del error, no solo después.
¿Es suficiente aumentar max_children?
Temporalmente para diagnóstico A. Calcule la RAM disponible; si el registro lento está concentrado, corrija el código primero: duplicar los trabajadores con código de bloqueo provoca una eliminación de OOM.
¿Cómo identificar el código de bloqueo?
slowlog PHP-FPM y herramienta de creación de perfiles. Síntoma: Todos los trabajadores ocupados, CPU baja. El mismo rastro en todas partes = cuello de botella identificado, no falta de trabajadores.
¿bajo demanda versus dinámico?
dinámico o bajo demanda para tráfico variable; estática para carga plana. ondemand ahorra RAM pero agrega latencia de inicio: prueba en preproducción.
PHP-FPM saturado indica una falta de cajas o cajeros estacionarios. Confundir los dos cuesta mucha RAM.
