...

Accodamento delle richieste PHP e limiti di elaborazione: configurazione ottimale per server stabili

L'accodamento delle richieste in PHP limita il numero di richieste che il server elabora contemporaneamente e quindi determina il tempo di risposta, il tasso di errore e l'esperienza dell'utente. Vi mostrerò come Limiti di elaborazione eliminare i colli di bottiglia e ottenere consegne coerenti grazie a parametri armonizzati.

Punti centrali

Affinché possiate iniziare subito, vi riassumo le viti di regolazione più importanti per PHP-FPM insieme.

  • pm.max_childrenCalcolare il limite massimo di processi PHP simultanei per adattarlo alla RAM.
  • listen.backlogMassimizzare il buffering a breve termine dei tentativi di connessione durante i picchi di carico.
  • pm.max_requestsRiciclare regolarmente i processi per evitare perdite di memoria e bloat.
  • Timeout: impostare request_terminate_timeout, max_execution_time e timeout del server web in modo coerente.
  • MetricheSe si raggiunge il numero massimo di bambini, controllare continuamente la coda di ascolto e gli slowlog.

Mi concentro su cifre chiave chiare e su effetti misurabili, in modo che ogni adeguamento a Limiti rimane tracciabile. Per ogni modifica, monitoro i log e i tempi di risposta prima di pianificare il passo successivo e aumentare o diminuire gradualmente i valori. In questo modo, prevengo effetti collaterali come lo swapping di memoria, che può Coda notevolmente più lunghi. Con questo approccio, tengo sotto controllo i picchi di carico e mantengo stabili i tempi di risposta. L'obiettivo è quello di ottenere un utilizzo equilibrato della capacità che Risorse in modo efficiente senza sovraccaricare l'host.

Come funziona la coda di richieste PHP in PHP-FPM

Ogni richiesta HTTP in arrivo richiede il proprio Lavoratore, e un worker serve solo una richiesta alla volta. Se tutti i processi sono occupati, le ulteriori chiamate finiscono nel file Coda e attendere che un processo si liberi. Se questa coda cresce, i tempi di risposta aumentano e gli errori come 502/504 si verificano più frequentemente. Per questo motivo, anziché puntare ciecamente sul massimo parallelismo, faccio attenzione a un rapporto ragionevole tra il numero di processi e la memoria disponibile. In questo modo, ottengo un tasso di throughput costante senza RAM o la CPU si stacca.

Selezionare le modalità di gestione dei processi in modo pulito

Oltre ai valori limite, il modalità pm reattività e consumo di risorse:

  • pm = dinamicoDefinisco start_servers, min_spare_servers e max_spare_servers. Questa modalità è il mio standard per i carichi variabili, perché reagisce rapidamente agli aumenti e tiene pronti i processi caldi.
  • pm = su richiestaI processi vengono creati solo quando necessario e vengono terminati dopo il process_idle_timeout. Ciò consente di risparmiare RAM per gli accessi poco frequenti (admin, staging, endpoint di cron), ma può portare a una perdita di RAM in caso di picchi improvvisi. Avviamenti a freddo e una latenza più elevata. Pertanto, lo uso in modo selettivo e con un generoso backlog.
  • pm = staticoUn numero fisso di processi. Ideale se ho un limite superiore rigido e latenze particolarmente prevedibili (ad esempio, proxy L7 di fronte a pochi ma critici endpoint). Il fabbisogno di RAM è chiaramente calcolabile, ma i processi non utilizzati occupano memoria.

Decido quale modalità si adatta al profilo di ciascun pool. Di solito uso la modalità dinamica per i frontend con carichi variabili, ondemand per i pool di utilità e statica per i servizi dedicati e critici per la latenza.

Determinare correttamente pm.max_children

Le leve più importanti sono pm.max_children, perché questo valore definisce quante richieste possono essere eseguite contemporaneamente. Calcolo la dimensione iniziale usando la regola empirica: (RAM liberamente disponibile - 2 GB di riserva) diviso per la memoria media per processo PHP. Come ipotesi approssimativa, utilizzo 40-80 MB per processo e inizialmente inizio con 200-300 processi su un host da 32 GB. Sotto carico vivo, aumento o diminuisco gradualmente e verifico se il tempo di attesa del processo Coda si riduce e il tasso di errore diminuisce. Se volete approfondire, potete trovare informazioni di base sui valori iniziali e limite su Ottimizzare pm.max_children.

Coordinare i valori di partenza, di riserva e di arretrato

Ho impostato pm.avvia_server a circa il 15-30% di pm.max_children, in modo che all'avvio sia disponibile un numero sufficiente di processi e non si verifichino avvii a freddo. Con pm.min_spare_servers e pm.max_spare_servers definisco una finestra ragionevole per i processi liberi, in modo che le nuove richieste non rimangano in attesa e allo stesso tempo non venga occupata memoria inutilizzata. Listen.backlog è particolarmente importante: Questo buffer del kernel contiene brevemente ulteriori tentativi di connessione quando tutti i lavoratori sono occupati. Per i picchi di carico, imposto valori elevati (ad esempio, 65535) in modo che il coda non si ferma prima del pool FPM. Informazioni di base più approfondite sull'interazione tra il server web, l'upstream e i buffer sono disponibili nella panoramica di Accodamento del server web.

Limitare i tempi di esecuzione delle richieste e riciclare i processi

Prevengo gli sbalzi di memoria con pm.max_requests, che riavvia ogni processo dopo X richieste. Le applicazioni non invasive spesso funzionano bene con 500-800, ma se si sospettano perdite di memoria le riduco a 100-200 e osservo l'effetto. Inoltre, request_terminate_timeout incapsula gli outlier, terminando le richieste estremamente lunghe dopo un tempo fisso. La coerenza è importante: mantengo il max_execution_time di PHP e i timeout del server web nello stesso corridoio, in modo che un livello non termini prima dell'altro. Questa interazione mantiene il Lavoratore libera e protegge la piscina dalla congestione.

Rendere visibili le code: Log e metriche

Leggo regolarmente i log di FPM e presto attenzione a bambini massimi raggiunti, perché questa voce indica che è stato raggiunto il limite superiore dei processi. Allo stesso tempo, monitoro la coda di ascolto, che rivela un crescente arretrato nel buffer di input. In combinazione con request_slowlog_timeout, ottengo le tracce dello stack per i punti lenti del codice e isolo i freni del database o dell'API. Metto in relazione upstream_response_time dai log del server web con request_time e codici di stato per restringere la fonte dei lunghi tempi di risposta. Questo mi permette di riconoscere se il collo di bottiglia è in PHP-FPM, il Banca dati o la rete a monte.

Profili di carico di lavoro: CPU-bound vs IO-bound

Per i processi pesanti per la CPU, scalare il valore di Parallelismo Sono cauto e mi oriento strettamente sul numero di vCPU, perché i processi aggiuntivi difficilmente portano throughput. Se si tratta principalmente di un carico IO con accessi a database o API esterne, posso consentire più processi purché il budget di RAM sia sufficiente. I checkout del commercio elettronico beneficiano di timeout più lunghi (ad esempio 300 s) per completare i metodi di pagamento senza cancellazioni. Intercetto le vendite flash impostando listen.backlog alto e aumentando la finestra di riserva. Le informazioni sull'equilibrio tra il numero di processi e le prestazioni dell'host sono contenute nella guida a PHP-Workers come collo di bottiglia.

Esempi di calcolo e dimensionamento

Per prima cosa calcolo la memoria per processo e poi ricavo una ragionevole Limite superiore off. Poi faccio un test con un carico reale e osservo se la coda diminuisce e il throughput aumenta. I valori iniziali conservativi riducono il rischio di swapping e mantengono uniforme il tempo di risposta. Poi perfeziono a piccoli passi per essere sicuro di notare eventuali effetti collaterali. La tabella seguente fornisce indicazioni sui valori iniziali e sugli effetti sulla Coda.

Parametri Effetto Valore iniziale (esempio) Suggerimento
pm.max_children Massima simultaneità Processi 200-300 (con 32 GB) Confronto con il budget di RAM e la dimensione del processo
pm.avvia_server Numero iniziale di lavoratori 15-30 % da max_bambini Evitate le partenze a freddo, ma riducete al minimo il funzionamento al minimo.
pm.min_spare_servers Gratuito Lavoratore Minimo z. B. 20 Inserimento diretto di nuove richieste
pm.max_spare_servers Lavoratore libero Massimo z. B. 40 Limitare il consumo di RAM dei processi inattivi
listen.backlog Buffer del kernel per i tentativi di connessione 65535 Coprono i picchi di carico e riducono le interruzioni delle connessioni
pm.max_requests riciclaggio Intervallo 500-800, con perdite 100-200 Ridurre al minimo il bloat di memoria e i blocchi
timeout_richiesta_termine Limite di richiesta rigido 300-600 s Coerente con i timeout di PHP e del server web

Modelli pratici per i pool FPM di PHP

Per un negozio con molti accessi in lettura, ho impostato una moderata Figure di processo e aumentare la finestra di riserva in modo che le richieste non vengano accodate. Per le pagine di contenuto con cache, spesso è sufficiente un numero significativamente inferiore di worker, purché NGINX o Apache forniscano contenuti statici in modo efficiente. Separo le configurazioni multi-pool in base alle parti dell'applicazione che hanno profili di memoria diversi, in modo che nessun pool pesante sostituisca gli altri. Definisco pool separati con le proprie regole di timeout per i lavoratori di cron o di coda. Questo è il modo in cui mantengo l'interattività Traffico gratuito e non rallenta le azioni dell'utente.

Timeout del server web, upstream e socket

Considero i timeout di FastCGI e del proxy da Nginx o Apache nella stessa finestra dei timeout di FPM, in modo che nessun livello termini troppo presto. Preferisco i socket Unix al TCP se entrambi i servizi sono in esecuzione sullo stesso host, perché la latenza rimane minima. Per le configurazioni distribuite, uso TCP con valori di keepalive stabili e un pool di connessioni sufficientemente ampio. Per un elevato parallelismo, nginx sincronizza worker_connections e i valori del backlog di FPM. Questo assicura che i reindirizzamenti rimangano veloci ed evita i tempi morti dovuti a connessioni troppo strette. A monte-Limiti.

Caching, OPCache e database come leve

Risolvo molti problemi dei server riducendo le operazioni più costose e minimizzando i costi di gestione. Tempo di risposta inferiore. Attivo OPCache, aumento il limite di memoria della cache in modo ragionevole e garantisco un'alta percentuale di hit della cache. Per ottenere risultati ricorrenti, utilizzo la cache delle applicazioni in modo che i processi PHP vengano completati più rapidamente. Per quanto riguarda il database, ottimizzo le query lente e attivo cache di query adatte al sistema utilizzato. Ogni millisecondo risparmiato riduce il carico sul database. Coda e aumenta il rendimento per lavoratore.

Meccanismi di emergenza e riavvii sicuri

Attivo soglia_riavvio_emergenza e emergency_restart_interval, in modo che il master FPM si riavvii se troppi bambini si bloccano in rapida successione. Questo riavvio controllato impedisce reazioni a catena e mantiene il servizio disponibile. Allo stesso tempo, ho impostato limiti chiari per la memoria e il numero di processi per evitare escalation. I controlli di salute sul lato upstream rimuovono automaticamente i backend difettosi dal pool e riducono i tassi di errore. In questo modo si mantiene il Disponibilità mentre indago sulla causa effettiva.

Regolazione fine del sistema operativo e dei limiti di systemd

Così che listen.backlog Se l'effetto è effettivo, regolo i limiti del kernel. Il valore OS net.core.somaxconn deve essere almeno pari al backlog impostato, altrimenti il sistema interrompe la coda. Verifico anche il numero di descrittori di file consentiti: Nel pool FPM posso impostare rlimit_files, a livello di servizio assicuro LimitNOFILE (systemd) e a livello di kernel fs.file-max. Il server web ha bisogno di riserve simili per non raggiungere prima i suoi limiti.

Per ottenere latenze più stabili, riduco vm.swappiness, in modo che il kernel non sposti prematuramente le pagine di memoria utilizzate attivamente. Nelle configurazioni critiche per la latenza, io disattivo Pagine trasparenti di grandi dimensioni, per evitare errori di pagina prolungati. Se FPM funziona via TCP, sincronizzo anche i parametri net.ipv4.tcp_max_syn_backlog e reuse/keepalive. Questi dettagli del sistema operativo sembrano poco appariscenti, ma decidono se le code liscio scadono o se le connessioni sono già state rifiutate prima dell'FPM.

Misurare il carico di memoria per processo

Invece di fare delle stime generalizzate, misuro la Consumi reali per lavoratore sotto carico reale. Uso strumenti come ps, smem o pmap, filtro per i bambini php-fpm e faccio una media dei valori RSS mentre le richieste sono in esecuzione. È importante tenere conto dell'uso di OPCache condivisa: la memoria condivisa non viene contata più volte. Ricavo pm.max_children dal valore medio e pianifico anche una riserva in modo che la macchina non si trovi in un collo di bottiglia anche durante i picchi. Scambio inclinazione.

Ripeto questa misurazione dopo i cambiamenti di funzione o di release. Nuove funzioni, maggiori dipendenze o modifiche ai framework possono aumentare significativamente l'ingombro per processo. In questo modo si mantiene il numero di processi realistico e la coda corta.

Stato di PHP FPM, ping e metriche live

Per una rapida valutazione della situazione, attivo pm.status_path e un Ping endpoint (ping.path/ping.response). Al di sopra di questo, posso vedere i dati chiave come le connessioni accettate, la lunghezza della coda di ascolto, i processi inattivi/occupati, i bambini massimi raggiunti e la loro progressione. Leggo periodicamente questi valori e stabilisco delle soglie: se la coda di ascolto aumenta in modo permanente, aumento i processi o elimino la causa delle richieste lente. Se il numero massimo di bambini raggiunti aumenta mentre l'inattività rimane bassa, il pool è troppo piccolo o bloccato da corridori lunghi.

Inoltre, separo i pool con profili diversi, in modo che i picchi in un'area (ad esempio, le importazioni API) non mettano in ginocchio il traffico interattivo. Per i casi diagnostici, aumento temporaneamente il log_level e lascio che lo slowlog catturi più campioni, ma poi lo riduco di nuovo per mantenere il carico di I/O basso.

Caricamenti, buffering e corpi di richiesta di grandi dimensioni

I caricamenti di grandi dimensioni possono bloccare inutilmente i lavoratori se PHP deve leggere prima il corpo della richiesta. Mi assicuro che il server web tamponi (ad esempio fastcgi_request_buffering per NGINX), in modo che FPM si avvii solo quando il corpo è completo. Ciò significa che nessun lavoratore si blocca durante il caricamento. Uso client_max_body_size, post_max_size e max_input_time per controllare quanto grandi e quanto lunghe possono essere le richieste senza mettere a rischio gli endpoint. Se ci sono file in mezzo, alloco una memoria temporanea sufficientemente veloce (SSD) per evitare inceppamenti del buffer.

Per gli endpoint con corpi molto grandi (ad esempio, esportazioni/importazioni), definisco pool dedicati con timeout propri e meno parallelismo. Questo lascia i lavoratori standard liberi e il Coda delle azioni importanti dell'utente.

Connessioni al database e confini del pool

La migliore impostazione di FPM non serve a nulla se l'unità di misura Banca dati precedentemente limitato. Allineo il numero massimo di processi PHP simultanei con la capacità del DB effettivamente disponibile. Per le connessioni persistenti o i pool di connessioni, mi assicuro che la somma di tutti i pool sia all'indirizzo max_connections rimane. Se ci sono molte query brevi, è utile limitare moderatamente il parallelismo di PHP, in modo che il DB non si agiti tra migliaia di sessioni.

Le transazioni lente causano rapidamente un arretramento nella coda di FPM. Pertanto, analizzo i tempi di attesa dei lock, l'utilizzo degli indici e i piani di query. Ogni riduzione del tempo di esecuzione del DB riduce immediatamente il tempo di attesa di PHP.Durata del documento e riduce la lunghezza delle code.

Rilasci e rollout senza picchi

Quando lancio nuove versioni, evito le cache fredde e le tempeste di processi. Uso ricaricare invece di riavvii bruschi, in modo che le richieste dei worker esistenti terminino in modo pulito (notare process_control_timeout). Riscaldo la OPCache in una fase iniziale, eseguendo i percorsi critici una volta prima della commutazione o lavorando con il precaricamento. In questo modo si evita che molti worker analizzino i file di classe nello stesso momento e che il Tempo di risposta aumenta a dismisura.

Con le strategie blu/verde o canarino, aumento gradualmente il carico e monitoro le pagine di stato. Solo quando la coda, il tasso di errore e le latenze rimangono stabili, aumento la percentuale di traffico. Questo approccio controllato protegge dai picchi di carico durante la distribuzione.

Specialità dei contenitori e delle macchine virtuali

Nei contenitori, la percezione Volume totale di stoccaggio spesso inferiore a quanto riportato dall'host. Allineo pm.max_children rigorosamente al limite di cgroup e pianifico una riserva contro l'OOM killer. I limiti di memoria in PHP (memory_limit) e l'ingombro per processo devono corrispondere, altrimenti un singolo outlier è sufficiente per terminare il contenitore.

Se non c'è swap nel contenitore, le cancellazioni difficili sono più probabili. Per questo motivo mantengo i processi conservativi, attivo il riciclo e monitoro i picchi RSS del carico di produzione. Diversi pool snelli sono spesso più robusti di un pool grande e monolitico.

Degradazione e contropressione controllabili

Se il Coda Mi affido al degrado controllato: fornisco deliberatamente 503 con retry after per gli endpoint non critici in caso di sovraccarico, riduco le funzionalità costose (ad esempio le ricerche live) e limito l'accesso parallelo agli hotspot. In questo modo il sistema rimane reattivo mentre io correggo la causa, invece di far andare in timeout tutti gli utenti.

Riassumendo brevemente

Porto Accodamento delle richieste in PHP sotto controllo, adattando abilmente il numero di processi concorrenti al budget di RAM e al tipo di carico. Valori elevati di backlog tamponano i picchi, i timeout a tutti i livelli si incastrano perfettamente e il riciclo rimuove i problemi di memoria striscianti. I registri e le metriche mi mostrano se la coda sta crescendo, dove le richieste sono bloccate e quando dovrei stringere i tempi. Con regolazioni attente e una cache mirata, riduco il tempo di elaborazione per richiesta e aumento il throughput. In questo modo, i server forniscono prestazioni costanti ed evitano costosi Timeout nella vita quotidiana.

Articoli attuali