php-fpm-optimering bestämmer hur många PHP-FPM-processer som får köras samtidigt, hur snabbt nya processer startar och hur länge de hanterar förfrågningar. Jag visar dig hur du pm.max_barn, pm, pm.start_servers, pm.min_spare_servers, pm.max_spare_servers och pm.max_requests så att din applikation reagerar snabbt under belastning och servern inte hamnar i swapping.
Centrala punkter
- pm-läge: Välj rätt mellan statisk, dynamisk eller ondemand så att processerna passar din trafik.
- pm.max_barn: Anpassa antalet samtidiga PHP-processer till RAM-minnet och den faktiska processförbrukningen.
- Start-/reservvärden: pm.start_servers, pm.min_spare_servers, pm.max_spare_servers balansera på ett meningsfullt sätt.
- återvinning: Med pm.max_requests kan du minska minnesläckor utan att skapa onödig overhead.
- Övervakning: Håll koll på loggar, status och RAM, och justera sedan stegvis.
Varför processhantering är viktigt
Jag styr med PHP-FPM Varje PHP-skript körs som en egen process, och varje parallell förfrågan behöver sin egen worker. Utan lämpliga begränsningar blockerar förfrågningar i köer, vilket leder till Tidsfrister och fel. Om jag sätter för höga övre gränser, äter processpoolen upp arbetsminnet och kärnan börjar swappa. Denna balans är ingen gissningslek: jag orienterar mig efter verkliga mätvärden och håller en säkerhetsmarginal. På så sätt förblir latensen låg och genomströmningen stabil, även om belastningen varierar.
Det är viktigt för mig att ha en tydlig målvärde: Hur många samtidiga PHP-körningar vill jag möjliggöra utan att RAM-minnet tar slut? Samtidigt kontrollerar jag om flaskhalsar snarare uppstår i Databas, hos externa API:er eller på webbservern. Endast när jag känner till flaskhalsen väljer jag rätt värden för pm, pm.max_children och liknande. Jag börjar konservativt, mäter och ökar sedan stegvis. På så sätt undviker jag hårda omstarter och oväntade avbrott.
De tre pm-lägena: static, dynamic, ondemand
Läget statisk håller alltid exakt pm.max_children processer tillgängliga. Detta ger mycket förutsägbara latenser, eftersom ingen startprocess behövs. Jag använder static när belastningen är mycket jämn och det finns tillräckligt med RAM-minne tillgängligt. Vid varierande efterfrågan slösar jag dock lätt bort resurser i static. Minne. Därför använder jag static specifikt där jag behöver konstant exekvering.
Med dynamisk Jag startar en startmängd och låter poolstorleken variera mellan min_spare och max_spare. Denna läge är lämpligt för trafik med vågor, eftersom arbetare skapas och avslutas efter behov. Jag håller alltid tillräckligt med inaktiva processer för att hantera toppar utan väntetid. För många inaktiva arbetare binder dock onödigt mycket resurser. RAM, varför jag håller reservmarginalen snäv. På så sätt förblir poolen rörlig utan att svälla upp.
I läget på begäran Det finns initialt inga arbetare, PHP-FPM startar dem först vid förfrågningar. Detta sparar minne under vilofaser, men den första träffen kostar lite latens. Jag väljer ondemand för sällan använda pooler, adminverktyg eller cron-ändpunkter. För mycket besökta webbplatser ger ondemand oftast sämre svarstider. Där föredrar jag klart dynamic med tydligt angivna reservvärden.
Dimensionera pm.max_children korrekt
Jag tror det. pm.max_barn från det tillgängliga RAM-minnet för PHP och det genomsnittliga minnet per arbetare. För detta reserverar jag först minne för systemet, webbservern, databasen och cacherna, så att systemet inte hamnar i Outsourcing körs. Jag delar det återstående RAM-minnet med den faktiska uppmätta processförbrukningen. Från teorin drar jag av 20–30 % säkerhetsmarginal för att kompensera för avvikelser och belastningstoppar. Jag använder resultatet som startvärde och observerar sedan effekten.
Jag beräknar den genomsnittliga processförbrukningen med hjälp av verktyg som ps, top eller htop och tittar på RSS/RES. Viktigt: Jag mäter under normal belastning, inte i viloläge. När jag laddar många plugins, ramverk eller stora bibliotek ökar förbrukningen märkbart per arbetare. Dessutom begränsar CPU:n kurvan: fler processer hjälper inte om en Enkel tråd-CPU-prestanda per förfrågan begränsad. Om du vill fördjupa dig i CPU-egenskaperna hittar du bakgrundsinformation om Enkelsträngad prestanda.
Jag är transparent med mina antaganden: Hur mycket RAM har PHP egentligen till sitt förfogande? Hur stor är en worker vid typiska förfrågningar? Vilka toppar uppstår? Om svaren stämmer ställer jag in pm.max_children, gör en mjuk omladdning och kontrollerar RAM, svarstider och felfrekvenser. Först därefter går jag vidare i små steg uppåt eller nedåt.
Riktvärden efter serverstorlek
Följande tabell ger mig Startvärden till hands. Den ersätter inte mätningar, men ger en god orientering för de första inställningarna. Jag anpassar värdena efter varje applikation och kontrollerar dem med övervakning. Om reserverna förblir outnyttjade ökar jag försiktigt. Om servern når RAM-gränsen drar jag tillbaka värdena.
| Server-RAM | RAM för PHP | Ø MB/arbetare | pm.max_barn (Start) | Användning |
|---|---|---|---|---|
| 1–2 GB | ~1 GB | 50–60 | 15–20 | Små webbplatser, bloggar |
| 4–8 GB | ~4–6 GB | 60–80 | 30–80 | Affärer, små butiker |
| 16+ GB | ~10–12 GB | 70–90 | 100–160 | Hög belastning, API, butiker |
Jag läser tabellen från höger till vänster: Passar det? Användning för projektet kontrollerar jag om RAM för PHP är realistiskt reserverat. Sedan väljer jag en arbetsstorlek som passar kodbasen och tilläggen. Därefter ställer jag in pm.max_children och observerar effekten i live-drift. Träffsäkerheten och stabiliteten ökar om jag dokumenterar dessa steg noggrant.
Ställa in start-, reserv- och begäranvärden
Med pm.start_servers Jag bestämmer hur många processer som ska vara tillgängliga omedelbart. För lågt ger kallstart under belastning, för högt binder onödigt RAM-minne. Jag riktar mig ofta mot 15–30 % från pm.max_children och avrundar om belastningen startar relativt lugnt. Vid trafiktoppar väljer jag en något högre startmängd så att förfrågningar inte rullar in innan tillräckligt många arbetare väntar. Denna finjustering minskar den första svarstiden avsevärt.
Värdena pm.min_spare_servers och pm.max_spare_servers definierar vilotiden. Jag håller så många lediga arbetare tillgängliga att nya förfrågningar kan få direkt åtkomst, men inte så många att viloprocesserna slösar bort minne. För butiker använder jag gärna ett snävare fönster för att jämna ut toppar. Med pm.max_förfrågningar Jag återanvänder processer efter några hundra förfrågningar för att begränsa minnesförskjutningen. För oansenliga applikationer väljer jag 500–800, vid misstanke om läckor går jag medvetet lägre.
Övervakning och felsökning
Jag kontrollerar regelbundet Loggar, statusidor och RAM. Varningar om att pm.max_children-gränserna har nåtts är för mig ett tydligt tecken på att det är dags att höja gränsen eller optimera koden/databasen. Om 502/504-fel upprepas tittar jag i webbserverns loggar och köerna. Tydliga fluktuationer i latensen tyder på för få processer, blockerande I/O eller för höga processkostnader. Jag tittar först på hårda fakta och reagerar sedan med små steg, aldrig med XXL-språng.
Jag upptäcker flaskhalsar snabbare när jag Väntetider mäta längs hela kedjan: webbserver, PHP-FPM, databas, externa tjänster. Om backend-tiden bara ökar för vissa rutter isolerar jag orsakerna genom profilering. Om väntetider uppstår överallt börjar jag med server- och poolstorleken. Det är också bra att titta på arbetsköer och processer i D-status. Först när jag förstår situationen ändrar jag gränserna – och dokumenterar varje ändring noggrant.
Webbserver och PHP-FPM i samverkan
Jag ser till att Webbserver-Limiteringar och PHP-FPM harmoniserar. För många samtidiga anslutningar på webbservern med för få arbetare orsakar köer och timeouts. Om arbetarna är uppskattade, men webbservern begränsar acceptansen, förblir prestandan låg. Parametrar som worker_connections, event-Loop och Keep-Alive påverkar direkt PHP-belastningen. En praktisk introduktion till finjusteringen ger tips om Trådpooler i webbservern.
Jag behåller Keep-Alive-tidsfönster i åtanke, så att tomgångsanslutningar inte blockerar arbetare i onödan. För statiska tillgångar använder jag aggressiv caching före PHP för att hålla arbetsbelastningen borta från poolen. Reverse-proxy-cacher hjälper dessutom när identiska svar hämtas ofta. På så sätt kan jag hålla pm.max_children lägre och ändå leverera snabbare. Mindre arbete per förfrågan är ofta den mest effektiva justeringsfaktorn.
Fina inställningsskruvar i php-fpm.conf
Jag går utöver grundvärdena och justerar Poolparametrar Bra. Med pm.max_spawn_rate begränsar jag hur snabbt nya arbetare får skapas, så att servern inte startar processer för aggressivt vid belastningstoppar och hamnar i CPU-thrashing. För ondemand anger jag med pm.process_idle_timeout fast, hur snabbt oanvända arbetare försvinner igen – för kort skapar startöverhead, för lång binder RAM. Vid lyssna-Socket väljer jag mellan Unix-Socket och TCP. En Unix-Socket sparar overhead och erbjuder tydlig rättighetsfördelning via listen.ägare, listen.group och listen.mode. För båda varianterna sätter jag listen.backlog tillräckligt hög för att inkommande bursts hamnar i kärnbuffertarna istället för att omedelbart avvisas. Med rlimit_files vid behov ökar jag antalet öppna filer per arbetare, vilket ger stabilitet vid många samtidiga uppladdningar och nedladdningar. Och när det behövs prioriteringar använder jag process.prioritet, för att behandla mindre kritiska pooler något mindre prioriterat på CPU-sidan.
Slowlog och skydd mot hängningar
För att synliggöra sega förfrågningar aktiverar jag Slowlog. Med begäran_slowlog_timeout definierar jag tröskeln (t.ex. 2–3 s) från vilken en stacktrace skickas till slowlog skrivs. På så sätt hittar jag blockerande I/O, dyra loopar eller oväntade låsningar. Mot riktiga hängningar använder jag begäran_avsluta_timeout, som bryts om en begäran tar för lång tid. Jag anser att dessa tidsfönster är förenliga med max_exekveringstid från PHP och webbserverns timeouts, så att inte ett lager bryts tidigare än det andra. I praktiken börjar jag konservativt, analyserar slowlogs under belastning och justerar tröskelvärdena stegvis tills signalerna är meningsfulla utan att loggen översvämmas.
Opcache, memory_limit och deras inverkan på storleken på arbetarna
Jag hänvisar till Opcache i min RAM-planering. Dess delade minnesområde räknas inte per arbetare, utan används gemensamt av alla processer. Storlek och fragmentering (opcache.minnes_förbrukning, interned_strings_buffer) påverkar uppvärmningstiden och träfffrekvensen avsevärt. En väl dimensionerad Opcache minskar CPU- och RAM-belastningen per förfrågan, eftersom mindre kod behöver kompileras om. Samtidigt noterar jag att memory_limit: Ett högt värde skyddar visserligen mot minnesbrist i enskilda fall, men ökar det teoretiska värsta fall-budgeten per arbetare. Jag planerar därför med ett uppmätt genomsnitt plus buffert, inte med det rena memory_limit. Funktioner som förladdning eller JIT ökar minnesbehovet – jag testar dem specifikt och räknar in den extra förbrukningen i pm.max_children-beräkningen.
Separera och prioritera pooler
Jag delar upp applikationer på flera pooler när lastprofilerna skiljer sig mycket åt. En pool för frontend-trafik, en för admin/backend, en tredje för cron/uppladdningar: På så sätt isolerar jag toppar och tilldelar differentierade gränser. För sällan besökta slutpunkter ställer jag in på begäran med kort idle-timeout för frontend dynamisk med snäv marginal. Om användare/grupp och eventuellt. chroot Jag ser till att isoleringen är ren, medan socket-rättigheter reglerar vilken webbserverprocess som får åtkomst. När prioriteringar krävs får frontenden mer pm.max_barn och eventuellt en neutral process.prioritet, medan Cron/Reports körs med mindre budget och lägre prioritet. På så sätt förblir användargränssnittet responsivt även när tunga jobb körs i bakgrunden.
Använda statusändpunkter på ett korrekt sätt
För att diagnostisera drifttiden aktiverar jag pm.status_path och valfritt ping.path per pool. I status ser jag Active/Idle-Worker, som Lista Kö, genomströmningsrelaterade mätare och slow request-metriker. En ständigt växande listkö eller konstant 0 idle-arbetare är varningssignaler för mig. Jag skyddar dessa slutpunkter bakom Auth och ett internt nätverk så att inga driftsdetaljer läcker ut. Dessutom aktiverar jag catch_workers_output, om jag snabbt vill samla in stdout/stderr från arbetarna – till exempel vid svårreproducerbara fel. Jag kombinerar dessa signaler med systemmetriker (RAM, CPU, I/O) för att avgöra om jag ska öka pm.max_children, justera reservvärden eller justera applikationen.
Särdrag i containrar och virtuella maskiner
På Containrar och små virtuella maskiner tar jag hänsyn till cgroup-begränsningar och risken för OOM-killer. Jag ställer in pm.max_children strikt efter Container-minnesgräns och testar belastningstoppar så att ingen arbetare stängs av. Utan swap i containrar är säkerhetsmarginalen särskilt viktig. För CPU-kvoter skalar jag antalet arbetare till det tillgängliga antalet vCPU: om applikationen är CPU-bunden leder mer parallellitet snarare till köer än till genomströmning. IO-bundna arbetsbelastningar tål fler processer så länge RAM-budgeten räcker. Dessutom sätter jag emergency_restart_threshold och emergency_restart_interval för masterprocessen, för att avvärja en kraschspiral om en sällsynt bugg drabbar flera barn på kort tid. På så sätt förblir tjänsten tillgänglig medan jag analyserar orsaken.
Smidiga distributioner och omladdningar utan avbrott
Jag planerar att Omladdningar så att pågående förfrågningar slutförs på ett korrekt sätt. En elegant omladdning (t.ex. via systemd reload) överför nya konfigurationer utan att avsluta öppna anslutningar. Jag håller socket-sökvägen stabil så att webbservern inte upplever något avbrott i anslutningen. Vid versionsbyten som ogiltigförklarar mycket Opcache värmer jag upp cachen (förladdning/uppvärmningsförfrågningar) för att begränsa latensspikarna direkt efter distributionen. Större ändringar testar jag först på en mindre pool eller i en Canary-instans med identisk konfiguration innan jag rullar ut värdena över hela linjen. Varje justering hamnar i min ändringslogg med tidsstämpel och skärmdumpar av mätvärden – det förkortar felsökningen om det uppstår oväntade bieffekter.
Burst-beteende och köer
Jag hanterar belastningstoppar med ett anpassat Ködesign av. Jag sätter listen.backlog så hög att kärnan kortvarigt kan buffra fler anslutningsförsök. På webbserverns sida begränsar jag det maximala antalet samtidiga FastCGI-anslutningar per pool så att de uppgår till pm.max_barn passar. På så sätt samlas bursts hellre kortvarigt i webbservern (billigt) än djupt i PHP (dyrt). Jag mäter Lista Kö i FPM-status: Om den stiger regelbundet ökar jag antingen antalet arbetare, optimerar cache-träfffrekvensen eller sänker aggressiva Keep-Alive-värden. Målet är att vid toppar Tid-till-första-byte stabil istället för att låta förfrågningar fastna i ändlösa köer.
Praktisk arbetsflöde för anpassningar
Jag börjar med en Revision: RAM-budget, processstorlek, I/O-profiler. Därefter anger jag konservativa startvärden för pm.max_children och pm-läget. Sedan kör jag belastningstester eller observerar verkliga topptider. Jag loggar alla ändringar inklusive mätvärden och tidsfönster. Efter varje justering kontrollerar jag RAM, latens P50/P95 och felfrekvenser – först därefter går jag vidare till nästa steg.
När jag upprepade gånger hamnar i en gränssituation eskalerar jag inte situationen omedelbart. Arbetare-antal. Först optimerar jag frågor, cache-träfffrekvenser och dyra funktioner. Jag flyttar IO-tunga uppgifter till köer och förkortar svarstiderna. Först när applikationen fungerar effektivt ökar jag poolstorleken. Denna process sparar resurser och undviker följdskador på andra ställen.
Typiska scenarier: Exempelvärden
På en 2 GB vServer reserverar jag ungefär 1 GB för PHP-FPM och ställer in en arbetarkonsumtion på cirka 50–60 MB. Jag börjar med pm.max_children på 15–20 och använder dynamic med en liten startmängd. Jag håller min_spare på 2–3 och max_spare på 5–6. Jag ställer in pm.max_requests på 500 så att processerna byts ut regelbundet. Dessa inställningar ger små projekt stabila responstider.
Med 8 GB RAM planerar jag oftast 4–6 GB för PHP och ställer in arbetstagarstorlekar på 60–80 MB. Detta resulterar i 30–80 underprocesser som startområde. pm.start_servers ligger på 15–20, min_spare på 10–15, max_spare på 25–30. pm.max_requests väljer jag mellan 500 och 800. Under belastning kontrollerar jag om RAM-toppen har utrymme och ökar sedan försiktigt.
I högbelastade konfigurationer med 16+ GB RAM reserverar jag 10–12 GB för FPM. Med 70–90 MB per arbetare hamnar jag snabbt på 100–160 processer. Om statisk eller dynamisk är lämpligt beror på belastningsformen. För permanent hög belastning är statisk övertygande, för vågformad efterfrågan är dynamisk övertygande. I båda fallen är konsekvent övervakning ett måste.
Undvika hinder och sätta prioriteringar
Jag blandar inte ihop antalet Besökare med antalet samtidiga PHP-skript. Många sidvisningar träffar cachar, levererar statiska filer eller blockeras utanför PHP. Därför dimensionerar jag pm.max_children efter uppmätt PHP-tid, inte efter sessioner. Om processerna är för sparsamt inställda ser jag väntande förfrågningar och ökande felfrekvenser. Om värdena är för höga tippar minnet över i swap och allt blir långsammare.
Ett vanligt misstag: fler processer innebär mer Hastighet. I själva verket är det balansen mellan CPU, IO och RAM som räknas. Om CPU går upp till 100 % och latensen ökar kraftigt, hjälper det knappast med fler arbetare. Det är bättre att eliminera det verkliga flaskhalsproblemet eller minska belastningen med hjälp av cache. Varför arbetare ofta är flaskhalsen förklaras i guiden till PHP-Worker som flaskhals.
Kortfattat sammanfattat
Jag fastställer först den verkliga RAM-förbrukning per arbetare och ställer in pm.max_children med buffert utifrån detta. Sedan väljer jag pm-läget som passar belastningsformen och balanserar start- och reservvärdena. Med pm.max_requests håller jag processerna fräscha utan onödig overhead. Loggar, status och mätvärden leder jag till en ren övervakning så att varje förändring förblir mätbar. På så sätt uppnår jag korta svarstider, stabila pooler och en serverbelastning som har reserver för toppar.


