Ajuste de php-fpm decide cuántos procesos PHP-FPM pueden ejecutarse simultáneamente, la velocidad a la que se inician los nuevos procesos y el tiempo que tardan en atender las solicitudes. Te mostraré cómo pm.max_hijos, pm, pm.start_servers, pm.min_spare_servers, pm.max_spare_servers y pm.max_requests de manera que tu aplicación responda rápidamente bajo carga y el servidor no entre en modo de intercambio.
Puntos centrales
- modo pm: elige correctamente entre estático, dinámico o bajo demanda para que los procesos estén disponibles según tu tráfico.
- pm.max_hijos: Alinear el número de procesos PHP simultáneos en la RAM con el consumo real de procesos.
- Valores iniciales/de reserva: equilibrar adecuadamente pm.start_servers, pm.min_spare_servers y pm.max_spare_servers.
- reciclaje: Mit pm.max_requests Speicherlecks abfedern, ohne unnötigen Overhead zu erzeugen.
- Monitoreo: Mantén un ojo en los registros, el estado y la RAM, y luego reajusta paso a paso.
Por qué es importante la gestión de procesos
Yo contribuyo con PHP-FPM la ejecución de cada script PHP como un proceso independiente, y cada solicitud paralela necesita su propio trabajador. Sin los límites adecuados, las solicitudes se bloquean en colas, lo que provoca Tiempos muertos y errores. Si establezco límites máximos demasiado altos, el grupo de procesos consume toda la memoria y el núcleo comienza a intercambiar. Este equilibrio no es una cuestión de adivinanzas: me baso en valores medidos reales y mantengo un margen de seguridad. De este modo, la latencia se mantiene baja y el rendimiento estable, incluso cuando la carga varía.
Para mí es importante una clara objetivo: ¿Cuántas ejecuciones PHP simultáneas quiero permitir sin agotar la RAM? Al mismo tiempo, compruebo si los cuellos de botella se producen más bien en la Base de datos, en API externas o en el servidor web. Solo cuando conozco el cuello de botella, selecciono los valores correctos para pm, pm.max_children y similares. Empiezo de forma conservadora, mido y luego aumento gradualmente. De esta manera evito reinicios bruscos y fallos inesperados.
Los tres modos pm: static, dynamic, ondemand
El modo estático siempre mantiene exactamente pm.max_children procesos disponibles. Esto proporciona latencias muy predecibles, ya que no es necesario ningún proceso de inicio. Utilizo static cuando la carga es muy uniforme y hay suficiente RAM disponible. Sin embargo, cuando la demanda varía, con static desperdicio fácilmente Memoria. Por eso utilizo static específicamente donde necesito una ejecución constante.
Con dinámico Inicio una cantidad inicial y dejo que el tamaño del grupo oscile entre min_spare y max_spare. Este modo es adecuado para el tráfico con picos, ya que los trabajadores se crean y se eliminan según sea necesario. Siempre mantengo suficientes procesos inactivos para absorber los picos sin tiempo de espera. Sin embargo, demasiados trabajadores inactivos consumen recursos innecesariamente. RAM, por lo que mantengo un margen de ahorro reducido. De este modo, la piscina se mantiene flexible sin hincharse.
En el modo a la carta Al principio no hay trabajadores, PHP-FPM solo los inicia cuando hay solicitudes. Esto ahorra memoria en los periodos de inactividad, pero el primer acceso tiene un ligero retraso. Yo elijo ondemand para pools que se usan poco, herramientas de administración o puntos finales cron. Para sitios web muy visitados, ondemand suele ofrecer peores tiempos de respuesta. En esos casos, prefiero claramente dynamic con valores de reserva bien configurados.
Dimensionar correctamente pm.max_children
Creo que pm.max_hijos de la RAM disponible para PHP y la memoria media por trabajador. Para ello, primero reservo memoria para el sistema, el servidor web, la base de datos y las cachés, para que el sistema no entre en Subcontratación funciona. Divido la RAM restante por el consumo real medido del proceso. De la teoría, resto un margen de seguridad de 20-30 % para compensar los valores atípicos y los picos de carga. Utilizo el resultado como valor inicial y luego observo el efecto.
Calculo el consumo medio del proceso con herramientas como P.D., top o htop y miro RSS/RES. Importante: mido bajo una carga típica, no en reposo. Si cargo muchos plugins, frameworks o bibliotecas grandes, el consumo por trabajador aumenta notablemente. Además, la CPU limita la curva: más procesos no ayudan si una Hilo único-Rendimiento de la CPU limitado por solicitud. Si desea profundizar en las características de la CPU, encontrará información sobre Rendimiento de un solo subproceso.
Mantengo mis suposiciones transparentes: ¿Cuánta RAM tiene realmente disponible PHP? ¿Qué tamaño tiene un trabajador en solicitudes típicas? ¿Qué picos se producen? Si las respuestas son correctas, establezco pm.max_children, realizo una recarga suave y compruebo la RAM, los tiempos de respuesta y las tasas de error. Solo entonces sigo subiendo o bajando poco a poco.
Valores orientativos según el tamaño del servidor
La siguiente tabla me da Valores iniciales a mano. No sustituye a las mediciones, pero proporciona una orientación sólida para los ajustes iniciales. Adapto los valores a cada aplicación y los compruebo mediante supervisión. Si quedan reservas sin utilizar, las aumento con cautela. Si el servidor alcanza el límite de RAM, reduzco los valores.
| RAM del servidor | RAM para PHP | Ø MB/trabajador | pm.max_hijos (Inicio) | Utilice |
|---|---|---|---|---|
| 1-2 GB | ~1 GB | 50-60 | 15-20 | Sitios pequeños, blogs |
| 4-8 GB | ~4-6 GB | 60-80 | 30-80 | Negocios, pequeñas tiendas |
| Más de 16 GB | ~10-12 GB | 70-90 | 100-160 | Alta carga, API, tiendas |
Leo la tabla de derecha a izquierda: ¿Encaja el Utilice Para el proyecto, compruebo si la RAM está reservada de forma realista para PHP. A continuación, selecciono un tamaño de trabajador que se adapte a la base de código y a las extensiones. Después, configuro pm.max_children y observo el efecto en el funcionamiento en vivo. La tasa de acierto y la estabilidad aumentan cuando documento estos pasos de forma clara.
Configurar los valores de inicio, reserva y solicitudes
Con pm.iniciar_servidores Determino cuántos procesos están disponibles de inmediato. Si el número es demasiado bajo, se producen arranques en frío bajo carga; si es demasiado alto, se ocupa RAM innecesariamente. A menudo me baso en 15-30 % de pm.max_children y redondeo si la carga comienza de forma más bien tranquila. En los picos de tráfico, elijo una cantidad inicial algo mayor para que las solicitudes no se acumulen antes de que haya suficientes trabajadores esperando. Este ajuste fino reduce significativamente el tiempo de respuesta inicial.
Los valores pm.min_servidores_de_repuesto y pm.max_spare_servers definen el intervalo de inactividad. Mantengo tantos trabajadores libres como para que las nuevas solicitudes puedan acceder directamente, pero no tantos como para que los procesos inactivos desperdicien memoria. En las tiendas, me gusta establecer un intervalo más estrecho para suavizar los picos. Con pm.max_requests Reciclo los procesos después de unos cientos de solicitudes para limitar la deriva de memoria. Para aplicaciones discretas, elijo entre 500 y 800, pero si sospecho que hay fugas, deliberadamente elijo un número más bajo.
Supervisión y resolución de problemas
Compruebo regularmente Registros, páginas de estado y RAM. Las advertencias sobre los límites alcanzados de pm.max_children son para mí una señal clara de que hay que aumentar el límite máximo u optimizar el código/la base de datos. Si se acumulan los errores 502/504, consulto los registros del servidor web y las colas. Las fluctuaciones significativas en la latencia indican que hay muy pocos procesos, que hay bloqueos de E/S o que los costes de los procesos son demasiado elevados. Primero miro los datos concretos y luego reacciono con pequeños pasos, nunca con saltos XXL.
Reconozco los cuellos de botella más rápidamente cuando utilizo la Tiempos de espera Mido a lo largo de toda la cadena: servidor web, PHP-FPM, base de datos, servicios externos. Si el tiempo de backend solo aumenta en determinadas rutas, aíslo las causas mediante perfiles. Si se producen tiempos de espera en todas partes, me centro en el tamaño del servidor y del pool. También es útil echar un vistazo a las colas de trabajadores y a los procesos en estado D. Solo cuando entiendo la situación, cambio los límites y documento cada cambio de forma clara.
Interacción entre el servidor web y PHP-FPM
Me aseguro de que Servidor webLos límites y PHP-FPM armonizan. Demasiadas conexiones simultáneas en el servidor web con muy pocos trabajadores provocan colas y tiempos de espera. Si se aumenta el número de trabajadores, pero el servidor web limita la aceptación, el rendimiento se ve afectado. Parámetros como worker_connections, event-Loop y Keep-Alive afectan directamente a la carga de PHP. Las siguientes indicaciones proporcionan una introducción práctica al ajuste fino: Pools de subprocesos en el servidor web.
Me quedo con Keep-Alive-Ventana de tiempo a la vista, para que las conexiones inactivas no bloqueen innecesariamente a los trabajadores. Para los activos estáticos, utilizo un almacenamiento en caché agresivo antes de PHP para mantener la carga de trabajo alejada del grupo. Las cachés de proxy inverso también ayudan cuando se recuperan con frecuencia respuestas idénticas. De este modo, puedo mantener pm.max_children más bajo y, aun así, entregar más rápido. Menos trabajo por solicitud suele ser el ajuste más eficaz.
Ajustes precisos en php-fpm.conf
Voy más allá de los valores fundamentales y ajusto los Parámetros de la piscina Bien. Con pm.max_spawn_rate Limito la velocidad a la que se pueden crear nuevos trabajadores para que el servidor no inicie procesos de forma demasiado agresiva durante los picos de carga y entre en un estado de sobrecarga de la CPU. Para ondemand, establezco con pm.process_idle_timeout fijo, ya que los trabajadores no utilizados desaparecen rápidamente: si es demasiado corto, se genera una sobrecarga de inicio; si es demasiado largo, se ocupa RAM. En el caso de escuchar-Socket, elijo entre Unix-Socket y TCP. Un Unix-Socket ahorra sobrecarga y ofrece una asignación de derechos clara a través de listen.owner, listen.group y modoescuchar. Para ambas variantes, utilizo lista.atraso suficientemente alto para que las ráfagas entrantes lleguen al búfer del núcleo en lugar de ser rechazadas inmediatamente. Con rlimit_files Si es necesario, aumento el número de archivos abiertos por trabajador, lo que aporta estabilidad cuando hay muchas descargas y cargas simultáneas. Y si hay que establecer prioridades, utilizo prioridad del proceso, para dar un tratamiento algo secundario a los grupos poco críticos en lo que respecta a la CPU.
Slowlog y protección contra bloqueos
Para hacer visibles las solicitudes lentas, activo el Slowlog. Con request_slowlog_timeout defino el umbral (por ejemplo, 2-3 s) a partir del cual un stack trace se envía al slowlog . Así encuentro bloqueos de E/S, bucles costosos o bloqueos inesperados. Contra los verdaderos bloqueos utilizo request_terminate_timeout, que se interrumpe bruscamente cuando una solicitud tarda demasiado en ejecutarse. Considero que estos intervalos de tiempo son coherentes con tiempo_de_ejecución_máximo de PHP y los tiempos de espera del servidor web, para que ninguna capa se interrumpa antes que otra. En la práctica, empiezo de forma conservadora, analizo los registros de lentitud bajo carga y ajusto los umbrales gradualmente hasta que las señales sean significativas, sin saturar el registro.
Opcache, memory_limit y su influencia en el tamaño de los trabajadores
Me refiero al Opcache en mi planificación de RAM. Su área de memoria compartida no se cuenta por trabajador, sino que es utilizada conjuntamente por todos los procesos. Tamaño y fragmentación (opcache.consumo_memoria, interned_strings_buffer) influyen considerablemente en el tiempo de calentamiento y en la tasa de aciertos. Un Opcache bien dimensionado reduce la presión sobre la CPU y la RAM por cada solicitud, ya que se recompila menos código. Al mismo tiempo, observo que límite_de_memoria: Un valor alto protege contra la falta de memoria en casos individuales, pero aumenta el presupuesto teórico en el peor de los casos por trabajador. Por lo tanto, planifico con un promedio medido más un margen, no con el memory_limit puro. Funciones como la precarga o JIT aumentan los requisitos de memoria; las pruebo específicamente e incluyo el consumo adicional en el cálculo de pm.max_children.
Separar y priorizar grupos
Dividir aplicaciones en varias piscinas cuando los perfiles de carga difieren considerablemente. Un grupo para el tráfico frontend, otro para admin/backend y un tercero para cron/uploads: así aíslo los picos y asigno límites diferenciados. Para los puntos finales poco frecuentados, establezco a la carta con un tiempo de espera inactivo reducido, para el frontend dinámico con un margen de ahorro reducido. Acerca de usuario/grupo y, si procede,. chroot Me encargo de que el aislamiento sea limpio, mientras que los derechos de socket regulan qué proceso del servidor web puede acceder. Cuando hay que establecer prioridades, el frontend recibe más. pm.max_hijos y, si procede, una neutral prioridad del proceso, mientras que Cron/Reports se ejecuta con un presupuesto menor y una prioridad más baja. De este modo, la interfaz de usuario sigue siendo receptiva, incluso cuando se están ejecutando tareas pesadas en segundo plano.
Utilizar correctamente los puntos finales de estado
Para el diagnóstico de tiempo de ejecución, activo pm.status_path y opcionalmente ping.path por grupo. En el estado veo trabajadores activos/inactivos que Cola de listas, contadores basados en el rendimiento y métricas de solicitudes lentas. Una cola de listas en constante crecimiento o trabajadores inactivos constantemente son señales de alarma para mí. Protejo estos puntos finales detrás de Auth y una red interna para que ningún detalle operativo se filtre al exterior. Además, activo captura_salida_trabajadores, si quiero recopilar rápidamente stdout/stderr de los trabajadores, por ejemplo, en caso de errores difíciles de reproducir. Combino estas señales con métricas del sistema (RAM, CPU, E/S) para decidir si aumento pm.max_children, actualizo los valores de reserva o intervengo en la aplicación.
Características especiales en contenedores y máquinas virtuales
En reciclaje de comida y máquinas virtuales pequeñas, tengo en cuenta los límites de cgroup y el peligro del OOM-Killer. Establezco pm.max_children estrictamente según el Límite de memoria del contenedor y compruebo los picos de carga para que no se cierre ningún trabajador. Sin intercambio en contenedores, el margen de seguridad es especialmente importante. En el caso de las cuotas de CPU, escalo el número de trabajadores al número de vCPU disponibles: si la aplicación está limitada por la CPU, un mayor paralelismo genera más colas que rendimiento. Las cargas de trabajo limitadas por E/S admiten más procesos, siempre que el presupuesto de RAM lo permita. Además, establezco umbral_de_reinicio_de_emergencia y intervalo_de_reinicio_de_emergencia para el proceso maestro, con el fin de evitar una espiral de fallos en caso de que un error poco frecuente afecte a varios hijos en poco tiempo. De este modo, el servicio sigue estando disponible mientras analizo la causa.
Implementaciones y recargas fluidas sin interrupciones
Estoy planeando Recargas de modo que las solicitudes en curso se completen correctamente. Un recarga elegante (por ejemplo, mediante systemd reload) aplica las nuevas configuraciones sin cerrar las conexiones abiertas. Mantengo estable la ruta del socket para que el servidor web no detecte ninguna interrupción de la conexión. En los cambios de versión que invalidan gran parte de Opcache, precargo la caché (solicitudes de precarga/calentamiento) para limitar los picos de latencia inmediatamente después de la implementación. Las modificaciones importantes las pruebo primero en un grupo más pequeño o en una instancia Canary con una configuración idéntica antes de implementar los valores a gran escala. Cada ajuste se registra en mi registro de cambios con una marca de tiempo y capturas de pantalla de las métricas, lo que acorta la búsqueda de errores en caso de que se produzcan efectos secundarios inesperados.
Comportamiento de ráfagas y colas
Compenso los picos de carga con un Diseño de colas ab. Yo apuesto por lista.atraso tan alto que el núcleo puede almacenar temporalmente más intentos de conexión. En el lado del servidor web, limito el número máximo de conexiones FastCGI simultáneas por grupo para que no superen pm.max_hijos encaja. De este modo, los picos se acumulan preferiblemente en el servidor web (más económico) que en PHP (más caro). Mido la Cola de listas En el estado FPM: si aumenta regularmente, aumento el número de trabajadores, optimizo las tasas de aciertos de la caché o reduzco los valores agresivos de Keep-Alive. El objetivo es, en los picos, el Tiempo hasta el primer byte mantener estable, en lugar de dejar que las solicitudes se pierdan en colas interminables.
Flujo de trabajo práctico para ajustes
Empiezo con un Auditoría: presupuesto de RAM, tamaño del proceso, perfiles de E/S. A continuación, establezco valores iniciales conservadores para pm.max_children y el modo pm. Después, realizo pruebas de carga u observo los picos de tiempo reales. Registro todos los cambios, incluidas las métricas y los intervalos de tiempo. Después de cada ajuste, compruebo la RAM, la latencia P50/P95 y las tasas de error; solo entonces paso al siguiente paso.
Cuando me encuentro repetidamente al límite, no escalo inmediatamente la situación. Trabajador-Número. Primero optimizo las consultas, las tasas de aciertos de la caché y las funciones costosas. Traslado las tareas con gran carga de E/S a colas y acorto las rutas de respuesta. Solo cuando la aplicación funciona de manera eficiente, aumento el tamaño del grupo. Este proceso ahorra recursos y evita daños consecuentes en otros lugares.
Escenarios típicos: valores de ejemplo
En un servidor virtual de 2 GB, reservo aproximadamente 1 GB para PHP-FPM y establezco un consumo de trabajadores de entre 50 y 60 MB. Para ello, empiezo con pm.max_children en torno a 15-20 y utilizo dynamic con una cantidad inicial pequeña. Mantengo min_spare en 2-3 y max_spare en 5-6. Establezco pm.max_requests en 500 para que los procesos se intercambien regularmente. Estos ajustes proporcionan tiempos de respuesta estables para proyectos pequeños.
Con 8 GB de RAM, suelo planificar entre 4 y 6 GB para PHP y establezco tamaños de trabajadores de 60-80 MB. Esto da como resultado un rango inicial de 30-80 procesos secundarios. pm.start_servers se sitúa entre 15 y 20, min_spare entre 10 y 15, y max_spare entre 25 y 30. pm.max_requests lo selecciono entre 500 y 800. Bajo carga, compruebo si el pico de RAM deja margen y, a continuación, lo aumento con precaución.
En configuraciones de alta carga con más de 16 GB de RAM, reservo entre 10 y 12 GB para FPM. Con 70-90 MB por trabajador, rápidamente llego a 100-160 procesos. Que sea más conveniente lo estático o lo dinámico depende del tipo de carga. Para una carga alta constante, lo estático es más convincente, mientras que para una demanda ondulada, lo dinámico es más adecuado. En ambos casos, es obligatorio realizar un seguimiento constante.
Evitar obstáculos y establecer prioridades
No confundo el número de Visitantes con el número de scripts PHP simultáneos. Muchas visitas a la página llegan a las cachés, proporcionan archivos estáticos o se bloquean fuera de PHP. Por eso dimensiono pm.max_children según el tiempo PHP medido, no según las sesiones. Si los procesos se configuran de forma demasiado austera, veo solicitudes en espera y un aumento de las tasas de error. Si los valores son demasiado altos, la memoria se desborda al swap y todo se ralentiza.
Un error frecuente: más procesos equivalen a más Velocidad. En realidad, lo que cuenta es el equilibrio entre CPU, IO y RAM. Si la CPU alcanza 100 % y la latencia se dispara, añadir más trabajadores apenas servirá de ayuda. Es mejor eliminar el verdadero cuello de botella o reducir la carga mediante la caché. La guía explica por qué los trabajadores suelen ser el cuello de botella. PHP Worker como cuello de botella.
Brevemente resumido
Primero determino el valor real. RAMConsumo por trabajador y, a partir de ahí, establezco pm.max_children con búfer. A continuación, selecciono el modo pm adecuado para el tipo de carga y equilibro los valores de inicio y de reserva. Con pm.max_requests mantengo los procesos actualizados sin una sobrecarga innecesaria. Dirijo los registros, el estado y las métricas a un sistema de supervisión limpio para que cada cambio sea medible. De este modo, consigo tiempos de respuesta cortos, grupos estables y una carga del servidor con reservas para los picos.


