Für eine sinnvolle PHP-FPM Kapazitätsplanung berechnest du zunächst, wie viele Worker in das verfügbare RAM-Budget passen. Davon getrennt schätzt du, wie viele Worker der tatsächlich beim Pool eintreffende Verkehr benötigt. pm.max_children begrenzt die gleichzeitig verfügbaren Worker pro Pool, ist aber weder eine Besucherzahl noch ein direkter Durchsatzwert. Auch CPU, Datenbank und Lastspitzen bestimmen, welche Einstellung im Betrieb tragfähig ist.
Was ein PHP-FPM Worker begrenzt
PHP-FPM verwaltet PHP-Prozesse in Pools. Ein Worker bearbeitet jeweils eine Anfrage; die Pool-Einstellung pm.max_children begrenzt die Zahl der gleichzeitig verfügbaren Worker und damit die gleichzeitig bearbeiteten PHP-Anfragen dieses Pools. Bei mehreren Pools gilt die Grenze jeweils für den betreffenden Pool, nicht automatisch für den gesamten Server.
Diese Zahl ist weder die Zahl angemeldeter Besucher noch ein direkter Wert für Requests pro Sekunde. Ein Besucher kann mehrere Anfragen auslösen, während ein angemeldeter Nutzer zwischen zwei Aktionen keinen Worker belegt. Umgekehrt kann ein einzelner langsamer Request einen Worker länger binden als mehrere kurze Anfragen hintereinander.
Auch nicht jeder Seitenaufruf erreicht PHP-FPM. Liefert der Webserver eine statische Datei direkt aus oder beantwortet ein vorgeschalteter Cache eine Anfrage vollständig, ist dafür je nach Architektur kein PHP-Worker nötig. Cache-Misses, eingeloggte Nutzer und Verwaltungsseiten können dagegen weiterhin PHP-Anfragen erzeugen und kurzfristig die Belegung erhöhen.
Für die Kapazitätsplanung sind deshalb zwei getrennte Fragen entscheidend: Wie viele Worker passen mit Reserve in das verfügbare RAM? Und wie viele Worker braucht der tatsächlich beim Pool eintreffende Verkehr, damit Anfragen nicht übermäßig lange warten? Ein hoher Wert für pm.max_children beantwortet keine dieser Fragen allein.
Selbst wenn ausreichend Speicher vorhanden ist, können CPU, Datenbank oder externe Dienste die praktische Kapazität begrenzen. Zusätzliche Worker ermöglichen dann zwar mehr parallele PHP-Arbeit, können aber gleichzeitig den Druck auf einen bereits langsamen Dienst erhöhen. Der Pool-Wert ist daher eine Betriebsgrenze und keine Leistungszusage.
Prozessmanager und Warteschlange verstehen
Der Prozessmanager legt fest, wann PHP-FPM Worker bereitstellt. Bei static entspricht die vorgehaltene Prozesszahl dem Wert von pm.max_children. Das macht die Zahl der Prozesse gut planbar, bindet aber auch bei geringer Auslastung Ressourcen. Die Obergrenze selbst muss weiterhin zum verfügbaren Speicher passen.
Bei dynamic passt FPM die Prozesszahl an: Startzahl sowie minimale und maximale Zahl freier Worker werden zusätzlich eingestellt. Bei ondemand entstehen Worker erst bei Bedarf und werden nach einer konfigurierten Leerlaufzeit beendet. Das kann bei selten genutzten Pools Ressourcen sparen; bei einer plötzlichen Lastspitze muss jedoch zunächst neue Prozesskapazität entstehen.
| Modus | Wichtige Einstellungen | Einsatz und Abwägung |
|---|---|---|
| static | pm.max_children | Feste Worker-Zahl; gut planbar, aber Ressourcenbindung im Leerlauf. |
| dynamic | pm.max_children, pm.start_servers, pm.min_spare_servers, pm.max_spare_servers | Anpassung an wechselnden Bedarf; freie und startende Worker müssen abgestimmt werden. |
| ondemand | pm.max_children, pm.process_idle_timeout | Worker bei Bedarf; spart bei selten genutzten Pools Ressourcen, Prozessstarts sind bei Lastanstieg zu berücksichtigen. |
Sind alle Worker beschäftigt, können weitere Anfragen in der Listener-Warteschlange auf einen freien Prozess warten. Der FPM-Status zeigt unter anderem die aktuelle und die maximale Warteschlange. Ein einzelner hoher Höchstwert beschreibt allerdings nicht, ob der Pool gerade überlastet ist; dafür braucht er einen zeitlichen Bezug.
Eine größere Warteschlange schafft keine zusätzlichen Worker und beschleunigt keine langsame Datenbank. Sie kann Anfragen vorübergehend aufnehmen, verlagert die Wartezeit aber lediglich vor die PHP-Bearbeitung. Für die Entscheidung über den Prozessmanager sind daher sowohl der typische Lastverlauf als auch die Folgen kurzer Spitzen wichtig.
Worker-Speicher richtig einordnen
Der Speicherbedarf eines Workers lässt sich nicht zuverlässig allein aus einer PHP-Konfigurationsgrenze ableiten. Für die Planung sind Prozessdaten unter passenden Lastbedingungen hilfreicher. Dabei macht es einen Unterschied, ob du den residenten Speicher eines einzelnen Prozesses ansiehst oder den Verbrauch einer ganzen Gruppe von PHP-FPM Workern einschätzen willst.
RSS beschreibt residenten Speicher eines Prozesses. Nutzen mehrere Worker dieselben Speicherseiten, können diese in ihrem jeweiligen RSS enthalten sein. Addierst du die RSS-Werte aller Worker, erscheinen gemeinsam genutzte Seiten dadurch unter Umständen mehrfach; die Summe ist deshalb keine saubere Aussage über den gemeinsam belegten physischen Speicher.
PSS verteilt gemeinsam genutzte Seiten anteilig auf die beteiligten Prozesse. Die Summe der PSS-Werte einer Prozessgruppe ist für deren Speicherplanung daher oft hilfreicher als die Summe der RSS-Werte. Sie bleibt dennoch eine Momentaufnahme: Ändert sich die Zahl der Prozesse, die Seiten teilen, ändern sich auch die jeweiligen Anteile.
Betrachte mehrere Worker bei typischen und auch bei speicherintensiven Requests. Ein frisch gestarteter Prozess oder ein einzelner Durchschnitt kann den späteren Bedarf unterschätzen. Die gesamte Pool-PSS bei verschiedenen Worker-Zahlen und Lastzuständen hilft, einen konservativen Näherungswert abzuleiten; eine Hochrechnung auf mehr Worker bleibt wegen veränderlicher gemeinsamer und privater Anteile unsicher.
Das PHP-memory_limit ist keine zuverlässige Angabe für den gesamten Betriebssystem-Speicher eines FPM-Prozesses und ersetzt diese Beobachtung nicht. Gemeinsam genutzten Speicher, etwa durch OPcache, solltest du nicht pauschal ein zweites Mal vom Budget abziehen, wenn er bereits anteilig in der verwendeten Pool-PSS enthalten ist. Andere Dienste und eine Reserve müssen trotzdem berücksichtigt werden.
RAM-Budget und Worker-Zahl berechnen
Ausgangspunkt ist das tatsächlich verfügbare RAM: auf einem Host der für die Dienste nutzbare Speicher, im Container das wirksame Speicherlimit. Ziehe davon den Bedarf des Betriebssystems, des Webservers, einer gegebenenfalls lokalen Datenbank und weiterer Dienste ab. Andere FPM-Pools und eine Reserve für schwankenden Verbrauch gehören ebenfalls in die Rechnung.
Der verbleibende Anteil ist das Pool-Budget. Für den Worker-Schätzwert beobachtest du die PSS-Summe der Pool-Worker bei verschiedenen Prozesszahlen und Lastzuständen. Berücksichtige typische Anfragen ebenso wie speicherintensive Endpunkte. Teile die jeweilige Summe durch die betrachtete Worker-Zahl und leite aus mehreren Beobachtungen einen vorsichtigen Näherungswert ab.
Die folgende Rechnung ist ein illustratives Rechenbeispiel, keine Messung. Die angenommenen Werte dienen nur dazu, den Rechenweg zu zeigen; sie sind keine Empfehlung für eine bestimmte Anwendung. Das Ergebnis wird auf eine ganze Worker-Zahl abgerundet.
| Rechenschritt | Annahme | Einordnung |
|---|---|---|
| Wirksames RAM-Limit | 4.096 MiB | Host- oder Containergrenze im Beispiel |
| Andere Dienste, Pools und Reserve | 2.048 MiB | Zusammen angenommener Abzug |
| Budget für den betrachteten Pool | 2.048 MiB | 4.096 minus 2.048 MiB |
| PSS-Näherungswert je Worker | 80 MiB | Angenommener konservativer Planungswert |
| Rechnerische RAM-Grenze | 25 Worker | 2.048 geteilt durch 80, abgerundet |
Die 25 Worker sind keine garantierte sichere Einstellung. PSS verteilt gemeinsam genutzte Seiten anteilig und verändert sich mit der Zahl der Prozesse, die diese Seiten teilen. Auch ein anderer Request-Mix kann den privaten Speicherbedarf verschieben; die Hochrechnung sollte daher gegen den beobachteten Gesamtverbrauch und das vorhandene Limit geprüft werden.
Ist gemeinsam genutzter Speicher wie OPcache bereits anteilig in der verwendeten PSS-Summe enthalten, ziehst du ihn nicht nochmals pauschal als vollständigen Zusatzposten ab. Plane dennoch Reserve für Speicheranteile ein, die deine Betrachtung nicht erfasst. Gerade bei einem Containerlimit zählt letztlich der Verbrauch aller Prozesse innerhalb der Grenze, nicht nur die geschätzte Worker-Summe.
Ein frisch gestarteter Worker allein ist als Grundlage wenig aussagekräftig: Er hat möglicherweise noch keinen anspruchsvollen Request bearbeitet. Vergleiche deshalb mehrere Zeitpunkte und halte fest, welche Endpunkte und wie viele Worker jeweils beteiligt waren. So lässt sich erkennen, ob der gewählte Näherungswert auch bei ungünstigeren, aber realistischen Betriebszuständen trägt.
Benötigte Worker aus Anfragen abschätzen
Die RAM-Rechnung beschreibt, wie viele Worker voraussichtlich Platz finden. Für den Bedarf zählt dagegen, wie viele PHP-Anfragen tatsächlich im betrachteten Pool eintreffen und wie lange sie einen Worker binden. Als erste Näherung gilt: mittlere gleichzeitig belegte Worker gleich PHP-Requests pro Sekunde multipliziert mit der mittleren Worker-Belegungszeit in Sekunden.
Illustratives Rechenbeispiel, keine Messung: Bei angenommenen 20 PHP-Requests pro Sekunde und einer mittleren Belegungszeit von 0,25 Sekunden sind im Mittel fünf Worker beschäftigt. Das ist ein Durchschnitt über den betrachteten Zeitraum. Er sagt weder, dass immer genau fünf Prozesse arbeiten, noch, dass fünf als Pool-Limit für kurze Spitzen ausreichen.
Für die Anfragezahl verwendest du nicht ungeprüft sämtliche Seitenaufrufe. Wenn ein Cache viele Antworten ausliefert, ohne PHP aufzurufen, belasten diese Treffer den Pool nicht. Umgekehrt können Cache-Misses, eingeloggte Besucher und Verwaltungszugriffe zeitweise mehr PHP-Arbeit auslösen, als ein über den ganzen Tag gebildeter Durchschnitt vermuten lässt.
Die Worker-Belegungszeit umfasst auch Wartezeiten innerhalb der Bearbeitung, etwa auf eine Datenbank oder einen externen Dienst. Sie ist nicht automatisch mit der im Browser sichtbaren Antwortzeit gleichzusetzen. Nach fastcgi_finish_request() kann PHP die Antwort bereits an den Client abgeschlossen haben und dennoch weitere Arbeit im Worker ausführen.
Für akzeptable Wartezeiten brauchst du Spielraum über der mittleren Belegung. Wie groß er sein muss, hängt unter anderem von Lastschwankungen, langsamen Endpunkten und dem gewünschten Antwortzeitziel ab. Eine Multiplikation von Spitzen-Requests pro Sekunde mit einer hohen Latenz-Perzentile kann ein vorsichtiger Szenariocheck sein, ist aber keine präzise Warteschlangenprognose.
Betrachte deshalb mehrere Zeiträume getrennt: Eine kurze Aktionsspitze und ruhiger Nachtverkehr können denselben Tagesmittelwert ergeben wie ein gleichmäßigerer Betrieb, stellen aber unterschiedliche Anforderungen. Steigt die Belegungszeit durch ein langsames Backend, wächst bei gleicher Ankunftsrate auch die mittlere Zahl gebundener Worker. Der Bedarf ist damit nicht allein eine Eigenschaft des Besucheraufkommens.
Pool-Einstellungen aus der Planung ableiten
Stelle nun die RAM-basierte Obergrenze dem geschätzten Bedarf einschließlich Spielraum gegenüber. Passt der Bedarf darunter, wähle einen vorsichtigen Startwert für pm.max_children, der das Budget nicht ausschöpfen muss. Im illustrativen Beispiel wären 25 die rechnerische RAM-Grenze, nicht automatisch die passende Einstellung; CPU und Backend können schon vorher begrenzen.
Liegt der geschätzte Bedarf über der RAM-Grenze, löst ein höheres Limit den Widerspruch nicht: Es kann den Host oder Container unter Speicherdruck setzen. Umgekehrt kann ein sehr niedriges Limit Anfragen warten lassen. Verbessere in diesem Fall etwa die Ausführungszeit oder Cache-Nutzung und prüfe, ob zusätzliche Ressourcen oder eine Begrenzung der Eingangslast nötig sind.
Bei dynamic legst du neben der Obergrenze die Startzahl sowie Mindest- und Höchstzahl freier Worker fest. Die Start- und Reservewerte sollten zur erwarteten Last passen und innerhalb der Obergrenze bleiben. Zu wenig vorgehaltene Kapazität kann bei plötzlicher Last zusätzlichen Startbedarf bedeuten; dauerhaft viele freie Prozesse verbrauchen dagegen Ressourcen.
Bei ondemand entstehen Worker erst bei Bedarf; die Leerlaufzeit bis zu ihrer Beendigung wird gesondert eingestellt. Das kann für selten genutzte Pools sinnvoll sein, erfordert aber bei schnellen Lastanstiegen besondere Aufmerksamkeit. Auch hier begrenzt pm.max_children die Zahl der gleichzeitig verfügbaren Worker des Pools.
Mehrere Websites auf demselben Host erhalten nicht unabhängig voneinander jeweils das gesamte freie RAM. Budgetiere ihre möglichen Pool-Maxima zusammen mit den übrigen Diensten und der Reserve. Eine gegebenenfalls konfigurierte globale FPM-Prozessgrenze kann zusätzlich greifen, ersetzt aber weder die einzelnen Pool-Budgets noch die Prüfung von CPU und Datenbankkapazität.
Prüfe nach Änderungen die tatsächliche Auslastung und Wartezeiten über geeignete Zeiträume, statt den Startwert als endgültig anzusehen. Bei Managed Hosting sind Prozessdaten oder Pool-Einstellungen möglicherweise nicht direkt zugänglich; nutze dann die Metriken und freigegebenen Optionen des Anbieters. Welche Einstellungen verfügbar sind, hängt außerdem von PHP-Version und Betriebsumgebung ab.
FPM-Status und Speicher beobachten
Die FPM-Statusseite zeigt, ob die geplanten Worker unter realer Last ausreichen. Schütze den Statusendpunkt vor öffentlichem Zugriff: Er kann sensible Angaben über Anfragen und Ressourcen preisgeben. Ein separat konfigurierter Status-Listener kann auch bei einem ausgelasteten Hauptpool erreichbar bleiben; prüfe seine Verfügbarkeit und Einrichtung für deine PHP-Version und Webserver-Konfiguration.
| Statuswert | Einordnung | Anschlussfrage |
|---|---|---|
| active processes / idle processes | Aktuell beschäftigte und freie Worker | Bleiben bei Lastspitzen freie Worker verfügbar? |
| listen queue / max listen queue | Aktuelle und bisher maximale Warteschlangenlänge | Wächst die Warteschlange während langsamer Antworten? |
| max children reached | Zähler für das Erreichen der Worker-Grenze bei dynamic oder ondemand | Steigt der Zähler im betrachteten Zeitraum? |
| slow requests | Zähler langsamer Anfragen | Fällt sein Anstieg mit längeren Antwortzeiten zusammen? |
Betrachte die Werte als Zeitreihen zusammen mit Anfragevolumen und Antwortzeiten. Ein alter Höchstwert der Warteschlange beweist keine aktuelle Überlastung; ebenso ist bei Zählern ihr Anstieg seit der letzten Beobachtung aussagekräftiger als der bloße Gesamtwert. Berücksichtige dabei den Poolstart beziehungsweise Neustarts, durch die sich der Bezugszeitraum ändert.
Für einen bekannten FPM-Worker kannst du auf einem Linux-System mit verfügbarer proc-Schnittstelle aggregierte Speicherwerte lesend abrufen. Ersetze PID durch die tatsächliche Prozess-ID; du benötigst die entsprechenden Zugriffsrechte. Wiederhole die Beobachtung für mehrere Worker und Lastzustände, statt aus einem einzelnen Prozess eine dauerhafte Poolgröße abzuleiten.
Langsame Requests und Warteschlangen untersuchen
Ein Shop kann viele aktive Worker anzeigen, obwohl nicht die PHP-Ausführung selbst der ursprüngliche Engpass ist. Warten Anfragen auf langsame Datenbankabfragen, bleiben die Worker währenddessen gebunden. Treffen weitere Anfragen ein, kann die Listener-Warteschlange wachsen und die Antwortzeit steigen, selbst wenn die CPU noch Reserven zeigt.
Eine höhere Worker-Grenze lässt in dieser Situation möglicherweise mehr Anfragen gleichzeitig zur Datenbank gelangen. Das kann den Backend-Druck erhöhen und Wartezeiten weiter verlängern. Vergleiche deshalb den zeitlichen Verlauf von FPM-Auslastung und Warteschlange mit Datenbanklast, langsamen Abfragen und externen Dienstaufrufen, bevor du die Grenze erhöhst.
Das FPM-Slowlog hilft, lange PHP-Aufrufe einzugrenzen: Für Anfragen über einer konfigurierten Schwelle kann FPM einen Backtrace protokollieren. Dieser zeigt einen Ausführungspunkt und ist kein vollständiges Profil der gesamten Anfrage. Wiederkehrende Stellen lassen sich mit Anfragedauer und Backend-Metriken abgleichen; die Anleitung zum Auswerten des PHP-FPM Slowlogs erläutert die weitere Analyse.
Auch ein Timeout ist von der eigentlichen Kapazität zu trennen. Bei nginx bezeichnet fastcgi_read_timeout den zulässigen Abstand zwischen aufeinanderfolgenden Lesevorgängen vom FastCGI-Server, nicht pauschal die gesamte Requestdauer. Ein höherer Wert kann längeres Warten zulassen, schafft aber weder zusätzliche Worker noch beschleunigt er die Datenbank.
Kapazitätsgrenzen und nächste Schritte
Reicht das RAM-Budget nicht für den geschätzten Bedarf, löst eine höhere Einstellung für pm.max_children den Zielkonflikt nicht: Zusätzliche Prozesse benötigen ebenfalls Speicher. Prüfe stattdessen, ob sich die Zahl der PHP-Anfragen oder die Dauer ihrer Worker-Belegung senken lässt. Welche Maßnahme sinnvoll ist, hängt davon ab, wo die beobachtete Last entsteht.
Ein besser genutzter Cache kann wiederholte Aufrufe abfangen, während schnellere PHP-Ausführung und Datenbankzugriffe Worker früher freigeben. Geeignete Hintergrundarbeit lässt sich aus dem unmittelbaren Anfragepfad auslagern; auch diese Arbeit benötigt allerdings eigene Ressourcen. Eine Lastbegrenzung schützt bei Spitzen das Backend, kann aber dazu führen, dass Anfragen warten oder abgewiesen werden.
Zusätzliches RAM kann eine höhere Worker-Zahl ermöglichen, wenn Speicher tatsächlich die maßgebliche Grenze ist. Sind CPU, Datenbank oder ein externer Dienst bereits ausgelastet, muss deren Kapazität ebenfalls berücksichtigt werden. Mehr Speicher allein garantiert deshalb weder kürzere Antwortzeiten noch einen höheren Durchsatz.
Steigt der Speicherbedarf einzelner Worker über ihre Lebensdauer, kann pm.max_requests deren regelmäßiges Ersetzen veranlassen. Das kann beim Umgang mit Speicherlecks in Drittbibliotheken helfen, behebt aber nicht deren Ursache. Beobachte nach einer Änderung weiterhin Pool-Speicher und Anfrageverhalten, statt den Neustartmechanismus als Ersatz für die Fehlersuche zu behandeln.
Für eine breitere Architekturentscheidung bietet der Vergleich von NGINX Unit und PHP-FPM Kontext; NGINX Unit ist archiviert und wird nicht mehr gepflegt. Unabhängig von der gewählten Architektur solltest du Änderungen anhand von Zeitreihen prüfen: Vergleiche bei ähnlichem Anfragevolumen Warteschlange, Worker-Auslastung, Speicher und Antwortzeiten. So lässt sich erkennen, ob eine Anpassung den Engpass tatsächlich entschärft oder lediglich verlagert hat.
Quellen und fachlicher Stand
Recherche-Stand:
Recherchestand: 4. November 2026. Verfügbarkeit von Status-Listener, Prozessdaten und Pool-Einstellungen für die eingesetzte PHP- und Linux-Version sowie die Hosting-Umgebung prüfen.
https://www.php.net/install.fpm.configuration
https://www.php.net/fpm.status.php
https://docs.kernel.org/7.0/filesystems/proc.html
https://www.kernel.org/doc/html/v6.12/filesystems/proc.html
https://www.php.net/manual/de/install.fpm.php
https://nginx.org/en/docs/http/ngx_http_fastcgi_module.html



