Resumen: Esta guía técnica explica cómo fluye una solicitud en PHP-FPM, qué ajustes impactan la latencia y una regla práctica para dimensionar pm.max_children por memoria.
Incluye una configuración de ejemplo, comprobaciones operativas y pasos para validar cambios con pruebas de carga.
Introducción
PHP-FPM (FastCGI Process Manager) administra pools de procesos PHP. Cada worker atiende una solicitud a la vez; la concurrencia total de un pool es el número de children activos.
Si faltan workers el resto de solicitudes se encolan en el socket o generan 502/504 cuando el backlog se desborda. El dimensionado correcto y unas pocas opciones clave evitan timeouts y picos de latencia.
Prerrequisitos
Acceso de administrador al host para editar la configuración de PHP-FPM y Nginx, ejecutar comandos de medición (ps, curl) y ejecutar pruebas de carga desde clientes de prueba.
Permisos para leer/crear archivos de slowlog y exponer pm.status_path y ping.path de forma segura (por ejemplo, accesible sólo desde localhost o una red de gestión).
Desarrollo
En esta sección describo el procedimiento recomendado: exponer métricas, medir memoria por worker, calcular pm.max_children y ajustar tiempos y backlog.
Procedimiento
- Exponer estado y slow logs.
- Medir RSS por worker bajo carga realista.
- Calcular pm.max_children por presupuesto de memoria.
- Ajustar pm.start_servers y los spares para mantener workers calientes.
- Hacer pruebas de carga y iterar.
Detalles y comandos útiles para cada paso.
[app]
user = www-data
group = www-data
listen = /run/php/php-fpm-app.sock
listen.owner = www-data
listen.group = www-data
listen.mode = 0660
listen.backlog = 1024
pm = dynamic
pm.max_children = 32
pm.start_servers = 8
pm.min_spare_servers = 8
pm.max_spare_servers = 16
pm.process_idle_timeout = 20s
pm.max_requests = 2000
request_terminate_timeout = 30s
request_slowlog_timeout = 2s
slowlog = /var/log/php-fpm/app.slow.log
pm.status_path = /status
ping.path = /ping
ping.response = pong
Lenguaje del código: TOML, también INI (ini)
Añade una ubicación en Nginx para exponer /status y /ping (restringe acceso):
location ~ ^/(status|ping)$ {
allow 127.0.0.1;
deny all;
include fastcgi_params;
fastcgi_pass unix:/run/php/php-fpm-app.sock;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
}
Lenguaje del código: Nginx (nginx)
Comandos para comprobar estado y medir memoria por worker:
curl -s http://127.0.0.1/status?full
# listar RSS de procesos php-fpm (ajusta el comando según tu sistema)
ps -o pid,rss,cmd -C php-fpm | head -n 60
Lenguaje del código: Bash (bash)
Regla práctica para calcular pm.max_children:
max_children = floor(pool_memory_budget_mb / per_child_rss_mb). Empieza 10–20% por debajo del valor teórico para dejar cabeza.
import http from 'k6/http';
import { check } from 'k6';
export const options = {
scenarios: {
steady: {
executor: 'constant-arrival-rate',
rate: 200,
timeUnit: '1s',
duration: '5m',
preAllocatedVUs: 200,
maxVUs: 1000,
},
},
thresholds: {
http_req_failed: ['rate<0.01'],
http_req_duration: ['p(95)<200'],
},
};
export default function () {
const res = http.get(`${__ENV.BASE_URL}/calc?x=1&y=2`);
check(res, {
'status is 200': r => r.status === 200,
'json has result': r => r.json('result') !== undefined,
});
}
Lenguaje del código: JavaScript (javascript)
Ejemplos
Mini caso: VM con 8 GB RAM, 2 GB reservados para sistema y servicios; 6 GB dedicados al pool. Muestras de RSS muestran mediana 120 MB por child.
Cálculo: floor(6000 / 120) = 50 → empezar con pm.max_children = 44 para dejar margen por fragmentación y OPcache.
Configuración de spares para absorber ráfagas en modo dynamic:
pm.start_servers = 12
pm.min_spare_servers = 12
pm.max_spare_servers = 24
pm.max_requests = 1500
Lenguaje del código: TOML, también INI (ini)
Validación: ejecutar carga sostenida y observar pm.status (idle, active, queue). Si la cola supera pm.max_children/4 durante >1 minuto, aumentar max_children si la memoria lo permite o optimizar endpoints lentos.
Checklist
- pm.status_path y ping.path habilitados y protegidos.
- request_slowlog_timeout = 1–2s para APIs; ruta de slowlog disponible.
- pm = dynamic y pm.max_children calculado por memoria.
- pm.max_requests en 1,000–3,000 según fuga observada.
- Alineación de request_terminate_timeout y timeouts de Nginx.
- OPcache con >20% de espacio libre en picos.
- listen.backlog ≥ 512 y límites de descriptors por encima del pico.
- Pools separados para admin/cron/colas si aplica.
Conclusión
PHP-FPM es medible: dimensiona por memoria, mantén workers calientes para ráfagas, activa slow logs y expón métricas. Valida con pruebas de carga y observa p95, cola y uso de memoria antes de escalar.
Si el patrón de trabajo no encaja (trabajos largos, streaming, altísima concurrencia ligera), considera arquitecturas alternativas en lugar de forzar más children.

Deja un comentario