PHP-FPM sizing: come dimensionare davvero i worker su WordPress
PHP-FPM lento o instabile non si aggiusta alzando numeri a caso. Devi misurare RAM per processo, coda richieste e comportamento del traffico.

Molti siti WordPress lenti non hanno un problema di codice. Hanno un pool PHP-FPM dimensionato male. Troppi pochi worker e le richieste si accodano. Troppi worker e il server finisce RAM, swap o OOM killer.
Questa guida ti spiega come dimensionare PHP-FPM in modo misurabile, senza formule da forum e senza copiare configurazioni di altri.
Se il sintomo iniziale è TTFB alto generalizzato, affianca questa lettura a Sito lento: 5 cause server-side e come risolverle. Se devi intervenire su un server già in crisi, puoi partire da SOS o dal servizio Performance Tuning.
TL;DR
Il sizing corretto di PHP-FPM si basa su questa sequenza:
- misura quanta RAM usa davvero un processo PHP
- definisci quanta RAM totale puoi assegnare a PHP
- calcola
pm.max_children - osserva coda, saturazione e swap
- ritocca solo dopo aver visto i dati
Il punto non è avere più worker possibile. Il punto è avere abbastanza worker da gestire il traffico, senza uccidere il resto del server.
Step 1: capisci che macchina stai gestendo
Prima domanda: quel server fa solo PHP o fa anche altro?
Esempi:
- web + db sullo stesso server
- web separato da db
- web + Redis + cron + queue workers
- hosting multi-sito con decine di pool
Se il server è condiviso, PHP non può mangiarsi tutta la RAM.
free -h
ps aux --sort=-%mem | head -20
Devi stimare la memoria riservata a:
- sistema operativo
- Nginx o Apache
- MySQL o MariaDB
- Redis, cron, agent monitoring
- margine di sicurezza
Step 2: misura la RAM per processo PHP
Questa è la metrica più importante.
ps -ylC php-fpm --sort:rss
Oppure, se vuoi una media semplice:
ps --no-headers -o rss -C php-fpm | awk '{sum+=$1; n++} END {if (n>0) print sum/n/1024 " MB"; else print "0 MB"}'
Come leggere il numero
Se il processo medio usa:
- 50 MB: WordPress abbastanza leggero
- 80-120 MB: stack normale con plugin e admin traffic
- 150 MB o più: plugin pesanti, WooCommerce, page builder, import o query brutte
Non usare il valore del processo più piccolo. Usa una media realistica o, meglio, il percentile alto durante carico normale.
Step 3: calcola la RAM assegnabile a PHP
Esempio pratico su server da 8 GB:
- 1.5 GB OS + servizi base
- 2 GB MySQL
- 0.5 GB Redis, monitoring, margine
- restano circa 4 GB per PHP
Se un processo medio PHP usa 80 MB:
4096 / 80 = 51
Quindi pm.max_children intorno a 45-50 ha senso.
Se ogni processo usa 140 MB:
4096 / 140 = 29
In quel caso impostare pm.max_children = 60 è una ricetta per l'OOM killer.
Step 4: controlla che ci sia davvero coda
Molti alzano pm.max_children senza sapere se PHP è veramente saturo.
Abilita lo status page del pool.
pm.status_path = /status
ping.path = /ping
Poi esponila solo in locale o dietro restrizioni e interroga:
curl -s http://127.0.0.1/status?full
Metriche chiave:
listen queuemax children reachedidle processesactive processes
Interpretazione pratica
listen queue > 0in modo ricorrente: richieste in attesamax children reached > 0: il pool sta saturando- molti
idle processescostanti: pool sovradimensionato
Step 5: scegli la modalità corretta
pm = dynamic
È quasi sempre la scelta giusta per WordPress.
pm = dynamic
pm.max_children = 45
pm.start_servers = 8
pm.min_spare_servers = 6
pm.max_spare_servers = 12
pm.max_requests = 500
pm = ondemand
Utile su server con tanti siti a basso traffico, dove vuoi risparmiare RAM quando non arriva traffico.
pm = static
Ha senso solo in casi particolari, con carico molto prevedibile e tuning rigoroso.
Configurazione di partenza sensata
Per un WordPress medio su Nginx con 4 GB dedicabili a PHP:
pm = dynamic
pm.max_children = 40
pm.start_servers = 6
pm.min_spare_servers = 4
pm.max_spare_servers = 10
pm.max_requests = 500
request_terminate_timeout = 120s
Non è una verità universale. È un punto di partenza da validare.
pm.max_requests: il parametro che molti ignorano
Serve a riciclare i processi dopo un certo numero di richieste.
Perché è utile:
- limita memory leak applicativi
- evita processi gonfiati da plugin o script lunghi
- stabilizza il comportamento nel tempo
Valori tipici:
3005001000
Se hai plugin o estensioni poco pulite, meglio stare più bassi.
Segnali di sizing sbagliato
Troppo basso
- TTFB alto a picchi
listen queuenon zero- utenti admin che si lamentano di lentezza intermittente
max children reachednei log o status
Troppo alto
- swap che sale
- MySQL che soffre improvvisamente
- OOM killer in
dmesg - tutto il server rallenta sotto carico
dmesg | grep -i "killed process"
vmstat 1 5
Errore classico: contare solo il frontend
Molti misurano il sito pubblico e ignorano:
- wp-admin
- wp-cron
- WooCommerce checkout
- import/export
- plugin backup
- scansioni o indexer
Il sizing va fatto sul traffico reale, non sulla home page in cache.
Quando il problema non è PHP-FPM
Non toccare PHP-FPM se il collo di bottiglia è altrove:
- database lento
- disco saturo o I/O scarso
- cache applicativa assente
- query esterne lente
- DNS o API terze parti
Per questo conviene incrociare i dati con MySQL buffer pool tuning: guida basata sui dati e con Monitoring, observability e NOC 24/7.
Procedura pratica di tuning
1. fotografia iniziale
free -h
ps --no-headers -o rss -C php-fpm | awk '{sum+=$1; n++} END {print sum/n/1024 " MB"}'
curl -s http://127.0.0.1/status?full
2. prima ipotesi
Calcoli RAM disponibile e pm.max_children.
3. modifica controllata
systemctl reload php8.2-fpm
4. osservazione
Per almeno 24-72 ore:
- RAM
- swap
- queue
- TTFB
- errori applicativi
5. secondo ritocco
Piccolo. Non raddoppiare i numeri a caso.
Quando questa guida non basta
Questa guida basta per pool PHP-FPM relativamente lineari. Non basta se:
- hai molti pool per molti clienti sullo stesso nodo
- usi container o orchestrazione con limiti rigidi
- il traffico è fortemente bursty
- c'è WooCommerce pesante con checkout concorrenti
- il database è già il collo di bottiglia
In questi casi ti serve una lettura trasversale di CPU, RAM, database, cache e traffico. Parti da audit gratuito o dal servizio Performance Tuning.
Checklist finale
- misurata RAM per processo
- stimata RAM disponibile a PHP
- calcolato
pm.max_children - abilitato status page
- controllati
listen queueemax children reached - verificato swap e OOM
- eseguito tuning incrementale
PHP-FPM non è un parametro da indovinare. È una capacità operativa da dimensionare. Quando lo tratti così, i siti smettono di essere “misteriosamente lenti”.
Pronto a smettere di occuparti dei server?
Audit scritto, zero impegni, report PDF con assessment della tua situazione.
Altri playbook collegati.
Guide che completano questo scenario operativo e ti aiutano a chiudere il cerchio tra diagnosi, prevenzione e continuità.
MySQL slow queries: playbook operativo per trovare il collo di bottiglia vero
Le slow query non si risolvono alzando la RAM a caso. Devi capire quali query rallentano davvero, perché, e in che ordine intervenire.
MySQL buffer pool: come calibrarlo davvero (senza magia)
La regola del 70-80% della RAM è una semplificazione pericolosa. Il buffer pool si calcola con dati, non con formule. Ecco come fare tuning evidence-based.
Sito lento: 5 cause che il 90% delle agenzie ignora (e come risolverle)
TTFB alto, pagine che caricano in 4+ secondi, clienti che si lamentano. Le cause sono quasi sempre lato server, non lato codice. Ecco dove guardare.