Guide

PHP-FPM: perché usare pm static per le massime prestazioni in produzione

Dario Fadda Giugno 8, 2026

Chi amministra server Linux con stack LEMP o LAMP sa bene che le prestazioni di PHP-FPM dipendono in larga misura dalla corretta configurazione del process manager (PM). L’impostazione predefinita pm = dynamic va bene per molti scenari, ma su server ad alto traffico con memoria disponibile può diventare un collo di bottiglia. Vediamo perché pm = static è spesso la scelta migliore per la produzione.

Le tre modalità di PHP-FPM process manager

PHP-FPM offre tre strategie per gestire i processi worker:

pm = dynamic

Il numero di processi varia dinamicamente in base ai parametri:

pm = dynamic
pm.max_children = 50
pm.start_servers = 5
pm.min_spare_servers = 5
pm.max_spare_servers = 35

PHP-FPM mantiene un pool variabile: avvia un certo numero di processi al boot, ne crea di nuovi sotto carico e termina quelli in eccesso in fase di inattività. È la modalità più flessibile ma anche quella con più overhead gestionale.

pm = ondemand

pm = ondemand
pm.max_children = 50
pm.process_idle_timeout = 10s

I processi vengono creati solo quando arrivano le richieste e terminati dopo un timeout di inattività. Ideale quando la memoria è scarsa o si gestiscono molti pool con traffico basso (tipicamente hosting condiviso con cPanel). Il limite è che su server con traffico intermittente ma costante, i processi vengono continuamente creati e distrutti, aggiungendo latenza esattamente nei momenti di picco.

pm = static

pm = static
pm.max_children = 100
pm.max_requests = 1000

Il numero di processi è fisso: pm.max_children worker vengono avviati al boot e restano sempre in memoria, pronti a rispondere. Non c’è overhead di creazione/terminazione dei processi.

L’analogia con il CPU governor

La scelta tra le tre modalità rispecchia esattamente quella del governor CPUFreq su Linux:

  • ondemand (CPU): scala la frequenza in base al carico, poi scende — stessa logica di pm ondemand
  • conservative (CPU): simile ma più graduale — analogo a pm dynamic
  • performance (CPU): massima frequenza sempre — equivalente a pm static

Su un server di produzione dedicato con carico consistente, proprio come si imposta il governor a performance, ha senso impostare PHP-FPM a static: si sacrifica un po’ di memoria per azzerare la latenza di spawn dei processi.

Quando usare pm static

pm = static è la scelta giusta quando:

  • Il server ha memoria abbondante rispetto al traffico atteso
  • Il carico è costante o con picchi frequenti (non siti dormenti)
  • Si gestisce un singolo pool PHP-FPM per applicazione
  • Si vuole la latenza minima possibile per ogni richiesta

Con i worker già in memoria, un picco di traffico improvviso viene assorbito senza dover attendere lo spawn di nuovi processi — che su sistemi sotto carico può richiedere decine di millisecondi.

Calcolare il valore corretto di pm.max_children

Impostare pm.max_children a caso è il classico errore. Troppo alto esaurisce la RAM, troppo basso crea code di attesa. Ecco come calcolarlo con dati reali.

Step 1: misurare la dimensione media di un worker

ps --no-headers -o rss -C php-fpm | awk '{ sum += $1; n++ } END { print sum/n/1024 " MB" }'

Questo comando mostra la dimensione media in MB del Resident Set Size (RSS) di ogni processo php-fpm in esecuzione. Eseguirlo sotto carico reale, non a server scarico.

Step 2: applicare la formula

pm.max_children = memoria_allocabile_MB / dimensione_media_worker_MB

Esempio concreto: se il worker medio pesa 60 MB e si possono allocare 6 GB a PHP-FPM:

pm.max_children = 6144 / 60 ≈ 100

Importante: non assegnare tutta la RAM disponibile a PHP-FPM. Lasciare sempre headroom per il kernel, Nginx/Apache, il database (MySQL/PostgreSQL) e la cache del filesystem. Una regola empirica è non superare il 60-70% della RAM totale per PHP-FPM su un server LEMP monolitico.

Step 3: impostare pm.max_requests

pm.max_requests = 1000

Con pm = static, i processi non vengono mai riavviati automaticamente per inattività. pm.max_requests definisce dopo quante richieste un worker viene riavviato — utile per prevenire memory leak in applicazioni PHP non perfette. Un valore alto (1000+) riduce l’overhead mantenendo una certa protezione. Solo se si ha certezza assoluta di assenza di leak si può usare pm.max_requests = 0.

Monitoraggio dei processi PHP-FPM

Per verificare il comportamento in produzione:

# Vedere tutti i processi PHP-FPM con CPU e memoria
top -bn1 | grep php-fpm

# Contare i worker attivi vs idle (richiede pm.status_path abilitato)
curl http://localhost/fpm-status

# Dimensione totale RSS usata da PHP-FPM
ps --no-headers -o rss -C php-fpm | awk '{ sum += $1 } END { print sum/1024 " MB totali" }'

Abilitare il status page di PHP-FPM nel pool configuration è fondamentale per il monitoring:

; in /etc/php/8.x/fpm/pool.d/www.conf
pm.status_path = /fpm-status

Quando ondemand e dynamic restano la scelta giusta

Non tutto è nero o bianco. pm ondemand e pm dynamic restano preferibili in questi scenari:

  • Hosting condiviso con 100+ pool: con tanti siti a traffico basso, tenere worker statici per ogni pool divorberebbe la RAM. cPanel stessa usa ondemand come default per questo motivo.
  • Server con memoria limitata: se la RAM è il collo di bottiglia, meglio sacrificare un po’ di latenza che andare in swap.
  • Ambienti containerizzati con autoscaling orizzontale: in un setup Kubernetes dove i pod scalano orizzontalmente, ha più senso un pm ondemand con confini ben definiti per container, lasciando che l’orchestratore gestisca il scaling.

Esempio di configurazione ottimale per server ad alto traffico

[www]
user = www-data
group = www-data

listen = /run/php/php8.3-fpm.sock
listen.owner = www-data
listen.group = www-data

pm = static
pm.max_children = 80
pm.max_requests = 2000

pm.status_path = /fpm-status

request_terminate_timeout = 60s
request_slowlog_timeout = 10s
slowlog = /var/log/php/fpm-slow.log

php_admin_value[error_log] = /var/log/php/fpm-error.log
php_admin_flag[log_errors] = on
php_admin_value[memory_limit] = 256M

Conclusione

Su server dedicati ad alto traffico con memoria disponibile, pm = static è quasi sempre la configurazione vincente. Elimina l’overhead del process manager, garantisce latenza costante e rende il comportamento del sistema prevedibile sotto carico. La chiave è misurare prima di configurare: il valore di pm.max_children deve essere basato sulla dimensione reale dei worker in produzione, non su stime.

Per ambienti multi-pool o con memoria limitata, ondemand rimane una scelta sensata. Ma per il classico server LEMP di produzione con una singola applicazione, passare a pm static è spesso uno dei miglioramenti più semplici e impattanti che si possano fare.


Fonte originale: PHP-FPM tuning: Using ‘pm static’ for max performance — LinuxBlog.io

💬 Unisciti alla discussione!


Questo è un blog del Fediverso: puoi trovare quindi questo articolo ovunque con @blog@spcnet.it e ogni commento/risposta apparirà qui sotto.

Se vuoi commentare su PHP-FPM: perché usare pm static per le massime prestazioni in produzione, utilizza la discussione sul Forum.
Condividi la tua esperienza, confrontati con altri professionisti e approfondisci i dettagli tecnici nel nostro 👉 forum community