Zum Inhalt springen
DSGVO-konform. Gehostet in DE.
14 Tage kostenlos testen →
PHP-FPMAntwortzeit-Perzentile502 und 504
Monitoring 14 Min. Lesezeit 9. Okt. 2026

Worker-Pool voll: Warum die Antwortzeit vor dem 502 kippt

Ein voller PHP-FPM-Pool erzeugt erst Wartezeit, dann 504 und 502. Welche Grenzen greifen und welche Messwerte die Warteschlange rechtzeitig sichtbar machen.

X

XICTRAQ

XICTRAQ

PHP-FPMAntwortzeitLasttest
511
Plätze hat die Warteschlange von PHP-FPM unter Linux ab Werk (PHP-Handbuch)
60 s
wartet nginx ab Werk auf die Antwort von PHP-FPM (nginx-Dokumentation)
151
gleichzeitige Verbindungen erlaubt MariaDB ab Werk (MariaDB-Dokumentation)
Worker-Pool voll: der Weg einer AnfrageDokumentierte Vorgaben von nginx, Linux, PHP-FPM und MariaDBnginx60 sfastcgi_read_timeoutWarteschlange511listen.backlog unter LinuxPHP-FPM-Poolpm.max_children erreichtMariaDB151max_connectionsAntwortzeit unter steigender Last60 s: nginx bricht ab, Besucher sieht 504Pool vollp95Mittelwertgleichzeitige AnfragenFrühe Signalep95 steigt stufenweiselisten queue über 0max children reached ab 1504: Frist abgelaufen502: Verbindung abgewiesen151 DB-Verbindungen belegt
Ein Onlineshop läuft seit Wochen stabil, dann kommt ein Newsletter, ein Fernsehbeitrag oder schlicht der erste volle Montagmorgen im Quartal. Die Startseite lädt noch, nur langsamer. Nach einigen Minuten brauchen Warenkorb und Suche ein Vielfaches der gewohnten Zeit, und erst danach tauchen die ersten Fehlerseiten auf: 504, später 502. Wer nur auf Fehlercodes achtet, sieht das Problem, wenn die Besucher schon gegangen sind. Die Ursache ist in vielen Fällen dieselbe: Der Pool der PHP-Worker ist voll, und jede weitere Anfrage wartet in einer Warteschlange, die niemand misst. Dieser Beitrag zeigt, welche Grenzen dabei hintereinander liegen, warum die Antwortzeit lange vor der Fehlerquote kippt und welche Messwerte eine volle Warteschlange früh sichtbar machen.

Vier Grenzen hintereinander: wo eine Anfrage wartet

Eine PHP-Anwendung hinter nginx durchläuft auf dem Weg zur Antwort mehrere Stationen, und jede hat ihre eigene Grenze. nginx nimmt die Verbindung des Besuchers an und reicht die Anfrage per FastCGI an PHP-FPM weiter. PHP-FPM verteilt sie auf einen Worker aus seinem Pool. Der Worker führt das Skript aus und fragt in aller Regel eine Datenbank. Solange überall Kapazität frei ist, merkt davon niemand etwas. Sobald eine Station voll ist, entsteht davor eine Schlange, und die Wartezeit addiert sich zur eigentlichen Bearbeitungszeit.

  • nginx wartet auf die Antwort von PHP-FPM. Die Vorgabe für fastcgi_read_timeout liegt bei 60 Sekunden (nginx-Dokumentation). Danach bricht nginx ab und liefert eine Fehlerseite.
  • Die Warteschlange des Sockets nimmt Verbindungen auf, für die gerade kein Worker frei ist. listen.backlog steht unter Linux ab Werk auf 511 (PHP-Handbuch).
  • Der Worker-Pool begrenzt über pm.max_children, wie viele Anfragen gleichzeitig bearbeitet werden (PHP-Handbuch). Jede weitere Anfrage wartet in der Schlange davor.
  • Die Datenbank begrenzt mit max_connections die Zahl gleichzeitiger Verbindungen, bei MariaDB ab Werk 151 (MariaDB-Dokumentation).

Die Warteschlange ist der unauffälligste Teil dieser Kette. Sie wird vom Kernel verwaltet, nicht von PHP. Den Wert aus listen.backlog kappt Linux stillschweigend auf den Inhalt von /proc/sys/net/core/somaxconn (Linux-Handbuchseite listen). Dort steht seit Linux 5.4 ab Werk 4096, in älteren Kerneln 128 (Linux-Handbuchseite listen). Auf einem älteren System kann die wirksame Schlange also deutlich kürzer sein als konfiguriert. Ist sie voll, bekommt der Client laut Handbuchseite entweder eine Abweisung mit ECONNREFUSED, oder die Verbindungsanfrage wird ignoriert, damit ein späterer Versuch gelingt (Linux-Handbuchseite listen). Beides sieht der Besucher nicht direkt, sondern als Wartezeit oder als Fehlerseite von nginx.

Vorgaben aus der Dokumentation, nicht Ihre Werte

Alle Zahlen in diesem Abschnitt sind dokumentierte Voreinstellungen. Paketverwalter, Hoster und Bedienoberflächen setzen oft andere Werte, manchmal je Pool verschieden. Welche Grenzen auf einem System wirklich gelten, zeigen erst nginx -T, php-fpm -tt, sysctl net.core.somaxconn und SHOW VARIABLES auf genau diesem System.

Warum die Antwortzeit in Stufen kippt

Ein voller Pool erzeugt zunächst keinen einzigen Fehler. Er erzeugt Wartezeit. Solange die Warteschlange Platz hat, landet jede neue Anfrage dort und wird irgendwann bedient. Wie lange das dauert, hängt vor allem von zwei Größen ab: wie viele Worker parallel arbeiten und wie lange eine Anfrage im Schnitt braucht. Das folgende Rechenbeispiel beruht auf der Annahme von 20 Workern und auf der Linux-Vorgabe von 511 Plätzen in der Warteschlange (PHP-Handbuch). Es ist bewusst vereinfacht und keine Messung.

Annahme: Zeit je AnfrageDurchsatz bei 20 WorkernWartezeit auf dem letzten der 511 PlätzeFolge für Besucher
0,4 Sekunden50 Anfragen pro Sekunderund 10 Sekundenspürbar langsam, noch keine Fehlerseite
1 Sekunde20 Anfragen pro Sekunderund 26 Sekundenviele Besucher geben auf, das Log bleibt ruhig
2,5 Sekunden8 Anfragen pro Sekunderund 64 Sekundenüber der Frist von 60 Sekunden: nginx liefert 504

Das Beispiel zeigt den Kern des Problems. Die Wartezeit wächst nicht mit der Last allein, sondern mit dem Produkt aus Schlangenlänge und Bearbeitungszeit. Wird die Datenbank langsamer, weil sie selbst unter Last steht, verlängert sich die Zeit je Anfrage, der Durchsatz sinkt, und die Schlange wird noch schneller länger. Die Kurve steigt deshalb nicht gleichmäßig, sondern in Stufen: Jede zusätzliche Verlangsamung im Hintergrund vervielfacht die Wartezeit vorne. Seiten, die aus einem Cache kommen, bleiben dabei schnell und verdecken den Engpass, weil sie PHP gar nicht erreichen. Warum ein vorgeschalteter Cache einen Ausfall am Ursprung verbergen kann, beschreibt der Beitrag über Origin-Monitoring hinter einem CDN.

Ein voller Worker-Pool meldet sich nicht mit Fehlern, sondern mit Wartezeit. Wer nur Fehlercodes zählt, sieht den Engpass zuletzt.

— XICTRAQ

Die Frist von nginx: wann aus Warten ein 504 wird

nginx wartet nicht unbegrenzt. Für FastCGI gilt die Direktive fastcgi_read_timeout mit der Vorgabe von 60 Sekunden (nginx-Dokumentation). Die Dokumentation beschreibt die Frist genau: Sie gilt nur zwischen zwei aufeinanderfolgenden Lesevorgängen und nicht für die Übertragung der gesamten Antwort. Sendet der FastCGI-Server in dieser Zeit nichts, wird die Verbindung geschlossen (nginx-Dokumentation).

Für die Warteschlange hat das eine unbequeme Folge. Die Verbindung zu PHP-FPM steht bereits, sobald der Kernel sie in die Schlange aufgenommen hat. nginx hat die Anfrage abgeschickt und wartet auf das erste Byte. Die Zeit, die eine Anfrage in der Schlange verbringt, zählt deshalb voll in die Frist hinein. Im Rechenbeispiel oben reicht eine Bearbeitungszeit von 2,5 Sekunden je Anfrage, damit die hinteren Plätze der Schlange die Frist nicht mehr schaffen. Für den Verbindungsaufbau selbst gilt eine zweite Frist, fastcgi_connect_timeout, ebenfalls mit der Vorgabe von 60 Sekunden (nginx-Dokumentation). Sie greift, wenn die Verbindung gar nicht erst zustande kommt, etwa weil der Kernel Verbindungsversuche bei voller Schlange ignoriert.

site.conf
# Beispiel: FastCGI-Fristen ausdrücklich setzen, hier mit den Werten der Vorgabe
location ~ \.php$ {
    include fastcgi_params;
    fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    fastcgi_pass unix:/run/php/www.sock;
    fastcgi_connect_timeout 60s;
    fastcgi_read_timeout 60s;
}

Die Frist höher zu setzen, verschiebt den 504 nur nach hinten. Der Besucher wartet dann länger auf dieselbe Fehlerseite, und die Schlange bleibt voll. Hilfreicher ist es, die Frist bewusst zu kennen, die Bearbeitungszeit deutlich darunter zu halten und die Wartezeit davor zu messen. Eine ausdrücklich gesetzte Frist hat außerdem einen praktischen Nutzen: Wer später die Konfiguration liest, sieht den Wert, statt ihn in der Dokumentation nachschlagen zu müssen.

Der Worker arbeitet weiter, obwohl niemand mehr wartet

Wenn nginx aufgibt, ist die Arbeit in PHP damit nicht beendet. Der Worker merkt vom Abbruch zunächst nichts und rechnet weiter, bis das Skript fertig ist oder eine eigene Grenze greift. Genau diese Worker fehlen dann den nächsten Anfragen in der Schlange. PHP-FPM kennt dafür request_terminate_timeout: die Frist für die Bearbeitung einer einzelnen Anfrage, nach der der Worker-Prozess beendet wird (PHP-Handbuch). Das Handbuch empfiehlt die Option für Fälle, in denen max_execution_time die Ausführung nicht stoppt, und nennt als Vorgabe den Wert 0, also aus (PHP-Handbuch).

Zwei Punkte sind dabei wichtig. Erstens läuft diese Frist erst, wenn ein Worker die Anfrage übernommen hat. Die Zeit in der Warteschlange davor zählt nicht mit. Zweitens beendet PHP-FPM den Prozess hart. nginx bekommt dann keine gültige Antwort und liefert einen 502. Ein Wert knapp unter der Frist von nginx, als Beispielwert etwa 55 Sekunden, sorgt dafür, dass hängende Skripte ihren Worker freigeben, statt ihn weiter zu blockieren, während nginx längst eine Fehlerseite ausgeliefert hat.

Warum reicht max_execution_time dafür nicht? Die Vorgabe liegt bei 30 Sekunden (PHP-Handbuch), aber auf Nicht-Windows-Systemen misst PHP damit nur die Zeit, in der das Skript selbst rechnet. Systemaufrufe, Stream-Operationen und Datenbankabfragen zählen laut Handbuch nicht mit (PHP-Handbuch). Ein Skript, das fast eine Minute auf eine überlastete Datenbank wartet, hat nach dieser Rechnung kaum Zeit verbraucht. Eine Ausnahme bilden Builds mit eingeschalteten Zend-Max-Execution-Timern, die die verstrichene Zeit messen; das Handbuch beschreibt sie bei der Direktive.

pool.d/www.conf
; Beispielwerte für einen Pool mit 20 Workern, keine Empfehlung
[www]
pm = dynamic
pm.max_children = 20
listen.backlog = 511
request_terminate_timeout = 55s
request_slowlog_timeout = 5s
slowlog = /var/log/php-fpm/www-slow.log
pm.status_path = /fpm-status
pm.status_listen = /run/php/status.sock
ping.path = /ping

Der Slowlog ist das Gegenstück zur harten Frist. Mit request_slowlog_timeout schreibt PHP-FPM nach Ablauf der eingestellten Zeit einen Backtrace der laufenden Anfrage in die Slowlog-Datei, ohne den Worker zu beenden; auch diese Option steht ab Werk auf 0, also aus (PHP-Handbuch). Der Backtrace zeigt, in welcher Funktion die Zeit vergeht, und bei einer vollen Schlange ist das oft eine Datenbankabfrage oder ein Aufruf an einen externen Dienst. Wie sich die Zeit bis zum ersten Byte grundsätzlich senken lässt, fasst der Leitfaden zur Optimierung der Server-Antwortzeit zusammen.

Die zweite Warteschlange: Datenbankverbindungen

Jeder Worker, der die Datenbank anspricht, braucht dafür eine Verbindung. Mehr Worker bedeuten deshalb auch mehr gleichzeitige Verbindungen. MariaDB begrenzt sie über max_connections, ab Werk auf 151 (MariaDB-Dokumentation). Diese Grenze teilen sich alle, die auf denselben Server zugreifen: jeder PHP-FPM-Pool, jeder Cronjob, jede Hintergrundverarbeitung und jede weitere Anwendung. Als Annahme gerechnet: Drei Pools mit je 50 Workern kommen allein auf 150 mögliche Verbindungen, bevor ein einziger Cronjob läuft.

MariaDB hält laut Dokumentation immer eine Verbindung für ein Konto mit SUPER- oder CONNECTION-ADMIN-Recht frei (MariaDB-Dokumentation). Das ist der Notzugang für die Administration. Er funktioniert nur, wenn das Konto der Anwendung dieses Recht nicht besitzt; sonst belegt die Anwendung auch diesen letzten Platz. Ist die Grenze erreicht, scheitert der Verbindungsaufbau sofort. Die Anwendung liefert dann schnell eine Fehlerseite, und genau diese schnellen Fehler verzerren später die Messung der Antwortzeit.

Verbindungen zählen

SHOW STATUS LIKE 'Threads_connected' zeigt die offenen Verbindungen, SHOW VARIABLES LIKE 'max_connections' die Grenze. Beide Werte gehören nebeneinander in dieselbe Übersicht.

Pools gegen die Grenze rechnen

Die Summe aller pm.max_children über alle Pools, dazu Cronjobs und Hintergrundprozesse, sollte mit Abstand unter max_connections bleiben. Sonst verschiebt ein größerer Pool den Engpass nur in die Datenbank.

Langsame Abfragen zuerst

Eine langsame Abfrage hält Worker und Verbindung gleichzeitig fest. Wer sie beschleunigt, entlastet beide Warteschlangen auf einmal und gewinnt mehr als mit jedem zusätzlichen Worker.

Anwendungskonto ohne SUPER

Das Konto der Anwendung braucht kein SUPER-Recht. Nur dann bleibt der reservierte Platz für die Administration frei, wenn alle anderen Verbindungen belegt sind.

Perzentile zeigen die Sättigung vor der Fehlerquote

Das Handbuch zur Site Reliability Engineering von Google beschreibt das Muster in allgemeiner Form. Ein Webdienst mit einer mittleren Latenz von 100 Millisekunden bei 1.000 Anfragen pro Sekunde kann leicht 1 Prozent Anfragen haben, die 5 Sekunden brauchen (Google SRE Book). Der Mittelwert verrät davon wenig. Das Buch nennt steigende Latenz einen häufig vorauslaufenden Indikator für Sättigung (Google SRE Book) und empfiehlt, das 99. Perzentil der Antwortzeit über ein kurzes Fenster zu messen, etwa eine Minute, weil es ein sehr frühes Signal liefert (Google SRE Book).

Für einen vollen Worker-Pool heißt das: Das p95 oder p99 steigt zuerst, der Mittelwert folgt träge, die Fehlerquote zuletzt. Hinzu kommt ein Messfehler, den das Buch ausdrücklich benennt. Ein Fehler, der schnell ausgeliefert wird, etwa weil die Datenbankverbindung fehlt, drückt die mittlere Antwortzeit nach unten, obwohl die Anfrage gescheitert ist (Google SRE Book). Antwortzeiten gehören deshalb getrennt nach erfolgreichen und fehlgeschlagenen Anfragen betrachtet. Außerdem verschlechtern sich viele Systeme laut dem Buch schon, bevor sie zu 100 Prozent ausgelastet sind (Google SRE Book). Ein Pool, der dauerhaft nahe an pm.max_children läuft, hat keinen Puffer mehr für die nächste Spitze. Wie Perzentile gelesen und für Alarme genutzt werden, erklärt der Beitrag über Antwortzeit-Perzentile p95 und p99.

Welche Kurven nebeneinander gehören

Das p95 der Antwortzeit, der Wert listen queue aus der FPM-Statusseite, die Zahl aktiver Worker und die offenen Datenbankverbindungen. Steigen p95 und Warteschlange gemeinsam, während die Fehlerquote noch flach ist, ist der Pool voll. Steigt nur das p95, liegt der Engpass eher in der Anwendung oder der Datenbank selbst.

502, 503 und 504 auseinanderhalten

Wenn aus Warten doch Fehler werden, sagt der Statuscode, an welcher Stelle die Kette gerissen ist. RFC 9110 definiert die drei Codes klar. Ein 502 bedeutet, dass ein Gateway oder Proxy vom dahinterliegenden Server eine ungültige Antwort erhalten hat (RFC 9110). Ein 503 zeigt an, dass der Server wegen vorübergehender Überlastung oder Wartung die Anfrage gerade nicht bearbeiten kann (RFC 9110). Ein 504 bedeutet, dass das Gateway vom dahinterliegenden Server keine rechtzeitige Antwort bekommen hat (RFC 9110).

CodeBedeutung nach RFC 9110Typische Ursache bei PHP-FPMWas das Monitoring sieht
502ungültige Antwort vom dahinterliegenden ServerSchlange voll und Verbindung abgewiesen, Worker durch request_terminate_timeout beendet oder abgestürztFehlerseite kommt oft schnell, die Antwortzeit wirkt unauffällig
503vorübergehend überlastet oder in Wartungbewusst geschaltete Wartungsseite oder eine Anwendung, die bei Überlast selbst abweistFehlerseite ohne lange Wartezeit, je nach Anwendung mit Hinweis auf einen späteren Versuch
504keine rechtzeitige Antwort vom dahinterliegenden ServerAnfrage lag zu lange in der Schlange oder im Worker, fastcgi_read_timeout abgelaufenAntwortzeit knapp über der Frist von nginx, vorher ein stufenweiser Anstieg

Die Reihenfolge, in der die Codes auftreten, ist selbst ein Befund. Steigt zuerst die Antwortzeit und folgen dann 504, wartet die Schlange zu lange. Kommen 502 ohne vorherigen Anstieg, weist entweder die volle Schlange Verbindungen ab oder Worker werden beendet. Das Fehlerprotokoll von nginx nennt je Anfrage den genauen Grund. Wie sich die Fehlerquote über alle Serverfehler beobachten lässt, beschreibt der Beitrag über die Serverfehlerrate im 5xx-Monitoring. Die Bedeutung einzelner Codes lässt sich mit dem Nachschlagewerkzeug für HTTP-Statuscodes prüfen.

Die FPM-Statusseite als Frühwarnung

PHP-FPM bringt eine eigene Statusseite mit, die genau die Werte liefert, die im Log fehlen. Sie wird über pm.status_path eingeschaltet und kann ihre Werte als Text, HTML, JSON, OpenMetrics oder XML ausgeben. Für den Engpass zählen vor allem vier Felder:

  • listen queue: die Zahl der Anfragen, die gerade auf einen freien Prozess warten (PHP-Handbuch). Alles über 0 heißt: Der Pool ist in diesem Moment voll.
  • max listen queue: der höchste Stand der Warteschlange seit dem Start des Pools. Er hält Spitzen fest, die zwischen zwei Abfragen liegen.
  • max children reached: zeigt, ob die Höchstzahl an Prozessen je erreicht wurde; dann steht dort 1 oder mehr, sonst 0 (PHP-Handbuch).
  • slow requests: die Zahl der Anfragen, die die eingestellte request_slowlog_timeout überschritten haben (PHP-Handbuch).

Eine Statusseite, die im selben Pool läuft wie die Anwendung, hat ein naheliegendes Problem: Wenn der Pool voll ist, wartet auch sie in der Schlange. Dafür gibt es pm.status_listen. Die Direktive legt eine eigene Adresse für Statusanfragen an und erzeugt dafür einen unsichtbaren Pool. Das Handbuch nennt genau diesen Fall: Die Statusseite bleibt erreichbar, auch wenn der Hauptpool mit lang laufenden Anfragen beschäftigt ist (PHP-Handbuch). Die Seite verrät Interna und gehört deshalb nicht offen ins Netz. Im folgenden Beispiel lässt nginx nur eine feste Adresse durch und verlangt zusätzlich ein geheimes Token im Anfragekopf.

status.conf
# Statusseite nur für den Monitoring-Abruf, Adresse und Token sind Beispiele
location = /fpm-status {
    allow 198.51.100.24;
    deny all;
    if ($http_x_status_token != "langes-zufallsgeheimnis") { return 404; }
    include fastcgi_params;
    fastcgi_param SCRIPT_FILENAME $fastcgi_script_name;
    fastcgi_pass unix:/run/php/status.sock;
}
$ curl -s -H "X-Status-Token: langes-zufallsgeheimnis" https://shop.example.invalid/fpm-status
pool: www process manager: dynamic start since: 86400 accepted conn: 412803 listen queue: 37 max listen queue: 511 listen queue len: 511 idle processes: 0 active processes: 20 total processes: 20 max active processes: 20 max children reached: 3 slow requests: 48

Die Beispielausgabe oben stammt aus einem Moment mit vollem Pool und ist gekürzt. Ein Wert über 0 bei listen queue, null freie Prozesse und max listen queue auf der Höhe von listen queue len zeigen gemeinsam: Die Schlange war bereits einmal randvoll. Der Ping-Endpunkt von PHP-FPM reicht als Ersatz nicht. Er antwortet mit Text und dem Statuscode 200 (PHP-Handbuch) und belegt damit nur, dass PHP-FPM antwortet, nicht, dass Worker frei sind. Wie ein aussagekräftiger Prüfendpunkt aufgebaut wird, zeigt der Beitrag über Health-Check-Endpunkte mit Tiefenprüfung.

Für eine Überwachung von außen eignet sich ein kleiner Umweg: Ein kurzes Skript in einem eigenen, kleinen Pool liest die Statusseite über den Status-Socket, fragt die Datenbank nach den offenen Verbindungen und gibt beides als knappes JSON aus. Den Endpunkt schützen dieselben Regeln wie oben, also feste Absenderadresse und Token. Scheitert eine der Abfragen, meldet das Skript das als eigenen Wert, statt eine Null einzusetzen, denn eine Null sähe aus wie eine leere Schlange.

antwort-statusendpunkt.json
{
  "ok": true,
  "fpm": {
    "listen_queue": 0,
    "max_children_reached": 3,
    "active_processes": 12,
    "total_processes": 20
  },
  "db": {
    "threads_connected": 41,
    "max_connections": 151
  }
}

Auf diesen Endpunkt lassen sich Prüfregeln setzen, die eine Warteschlange melden, bevor Besucher sie spüren. Welche Prüfregeln sich für Antworten einer Schnittstelle eignen, vertieft der Beitrag über Assertions und Schwellenwerte im API-Monitoring.

  • status_code gleich 200: Der Endpunkt selbst antwortet.
  • json_path $.fpm.listen_queue kleiner als 1: Die Warteschlange ist leer.
  • json_path $.db.threads_connected kleiner als 120: ein selbst gewählter Abstand zur Grenze von 151 (MariaDB-Dokumentation).
  • max children reached ist ein Zähler seit dem Start des Pools. Er gehört in den Verlauf, nicht in eine feste Prüfregel, denn nach dem ersten Erreichen bleibt er bis zum nächsten Neustart über 0.

Die Grenze messen, bevor Besucher sie finden

Wo genau die Kette reißt, lässt sich nicht aus der Dokumentation ablesen, nur messen. Ein Lasttest beantwortet drei Fragen: Bei wie vielen gleichzeitigen Anfragen beginnt die Schlange? Wie schnell steigt ab dann das p95? Und welcher Fehler kommt zuerst, 502 oder 504? Belastet werden ausschließlich eigene Systeme, am besten eine Staging-Umgebung mit denselben Grenzen wie die Produktion.

  1. Die wirksamen Grenzen auslesen: nginx -T für die Fristen, php-fpm -tt für den Pool, SHOW VARIABLES für die Datenbank und sysctl net.core.somaxconn für die Warteschlange.
  2. Eine Staging-Umgebung mit denselben Werten aufsetzen. Ein Test gegen andere Grenzen misst ein anderes System.
  3. Die Last stufenweise erhöhen und jede Stufe einige Minuten halten, damit sich die Schlange füllen kann.
  4. Während jeder Stufe p95, listen queue, max children reached und die offenen Datenbankverbindungen mitschreiben.
  5. Festhalten, welcher Fehler zuerst auftritt. 504 deutet auf zu lange Wartezeit, 502 auf abgewiesene Verbindungen oder beendete Worker.
  6. Immer nur eine Grenze ändern und neu messen. Wer Pool, Schlange und Datenbank zugleich verstellt, weiß danach nicht, welche Änderung gewirkt hat.

Lastspitzen sind oft vorhersehbar. Wie sich ein Shop auf das Weihnachtsgeschäft vorbereitet, beschreibt der Beitrag über Lastspitzen im vierten Quartal. Wer Messreihen später mit dem Vorjahr vergleichen will, muss verschobene Aktionstage berücksichtigen; das zeigt der Beitrag zum Vorjahresvergleich mit Kalenderversatz. Und wer Messreihen aufbewahrt, hat zugleich Unterlagen, die bei Nachweisen für die Cyberversicherung helfen können.

Das Muster in einem Satz

In vielen Fällen steigt zuerst das p95, dann füllt sich die Warteschlange, und erst danach folgen Fehlercodes. Wer die ersten beiden Signale misst, hat Zeit zu handeln, bevor Besucher Fehlerseiten sehen.

Wie XICTRAQ die frühen Signale sichtbar macht

XICTRAQ misst von außen, so wie ein Besucher. Für einen vollen Worker-Pool ist das die passende Perspektive, denn die Wartezeit in der Schlange taucht in keinem PHP-Log auf, wohl aber in der Antwortzeit, die ein Besucher erlebt. Die Werte aus dem Inneren des Servers kommen über den geschützten Statusendpunkt hinzu.

Antwortzeit als p95

Das Uptime-Monitoring speichert zu jedem Check den Statuscode und die Antwortzeit und bildet das p95 aus mehreren Standorten. Ein stufenweiser Anstieg wird im Verlauf sichtbar, bevor die ersten Fehlerseiten auftauchen.

Prüfregeln auf den Statusendpunkt

Im API-Monitoring lassen sich Prüfregeln auf Statuscode, Antwortzeit, JSON-Pfad und Textinhalt setzen, mit Operatoren wie kleiner als, gleich oder Wertebereich. Eigene Anfrageköpfe für ein Token werden verschlüsselt gespeichert.

Alarm bei langsamer Antwort

Der Alarm für langsame Antworten beobachtet ein gleitendes P95. Die Schwelle ist entweder fest oder eine adaptive Baseline mit einem eigenen Normalwert für jede Stunde der Woche. Wohin die Meldung geht, regelt die Alarmierung mit Benachrichtigungen.

Statuscode im Verlauf

Jeder Check hält den gelieferten Statuscode fest. Ob zuerst 504 oder 502 kam, lässt sich im Verlauf nachlesen, ohne Serverlogs von mehreren Rechnern zusammenzusuchen.

Wie eine Baseline zwischen einer normalen Montagsspitze und einem echten Engpass unterscheidet, beschreibt der Beitrag über Anomalie-Erkennung im Website-Monitoring. Was XICTRAQ nicht leistet: Es schaut nicht selbst in den Server hinein. Die Werte der FPM-Statusseite kommen nur dann an, wenn ein geschützter Endpunkt sie nach außen gibt, wie oben beschrieben.

Quellen und Dokumentation

Dieser Beitrag stützt sich auf: das PHP-Handbuch (Konfiguration von PHP-FPM, FPM-Statusseite, Laufzeitkonfiguration und set_time_limit), die nginx-Dokumentation zum Modul ngx_http_fastcgi_module, die Dokumentation der Serversystemvariablen von MariaDB, die Linux-Handbuchseite listen(2), RFC 9110 (HTTP Semantics) sowie das Kapitel „Monitoring Distributed Systems“ aus dem Google SRE Book. Alle genannten Werte sind dokumentierte Voreinstellungen; auf einem konkreten System können abweichende Werte gelten. Das Rechenbeispiel beruht auf Annahmen und ist keine Messung.

Warum lädt die Seite langsam, obwohl im PHP-Log keine Fehler stehen?
Weil die Wartezeit vor PHP entsteht. Eine Anfrage, die in der Warteschlange des Sockets liegt, hat noch keinen Worker erreicht und kann deshalb nichts protokollieren. Erst wenn nginx nach Ablauf von fastcgi_read_timeout aufgibt, erscheint ein Eintrag im Fehlerprotokoll von nginx. Die FPM-Statusseite mit dem Feld listen queue und das p95 der Antwortzeit zeigen den Zustand früher.
Reicht es, pm.max_children einfach zu erhöhen?
In der Regel nicht ohne Rechnung. Jeder zusätzliche Worker braucht Arbeitsspeicher und meist eine Datenbankverbindung. MariaDB erlaubt ab Werk 151 gleichzeitige Verbindungen (MariaDB-Dokumentation), und die teilen sich alle Pools und Cronjobs. Ein größerer Pool ohne Blick auf die Datenbank verschiebt den Engpass nur nach hinten. Sinnvoll ist eine Erhöhung, wenn Speicher und Verbindungen nachweislich Luft haben und die Bearbeitungszeit je Anfrage nicht das eigentliche Problem ist.
Hilft eine kürzere Warteschlange über listen.backlog?
Sie ändert, wie der Engpass sichtbar wird, nicht ob er entsteht. Unter Linux liegt die Vorgabe bei 511 Plätzen (PHP-Handbuch), und der Kernel kappt größere Werte auf net.core.somaxconn (Linux-Handbuchseite listen). Eine kürzere Schlange lässt Anfragen früher scheitern, statt sie lange warten zu lassen. Ob das für Besucher besser ist, hängt vom Angebot ab und lässt sich im Lasttest klären.
Warum sehe ich mal 502 und mal 504?
Die beiden Codes stehen für verschiedene Bruchstellen. Ein 504 entsteht, wenn nginx innerhalb der Frist keine Antwort bekommt, typischerweise weil die Anfrage zu lange in der Schlange oder im Worker lag. Ein 502 entsteht, wenn nginx eine ungültige oder gar keine Antwort erhält, etwa weil die volle Schlange die Verbindung abweist oder request_terminate_timeout den Worker beendet hat. Das Fehlerprotokoll von nginx nennt den genauen Grund je Anfrage.
Genügt der Ping-Endpunkt von PHP-FPM als Überwachung?
Nein, er beantwortet eine andere Frage. Der Ping antwortet mit Text und dem Statuscode 200 (PHP-Handbuch) und zeigt damit, dass PHP-FPM antwortet. Ob Worker frei sind und wie lang die Schlange ist, sagt er nicht. Dafür braucht es die Statusseite, am besten über pm.status_listen in einem eigenen Pool, damit sie auch bei vollem Hauptpool antwortet.
Wie oft sollte der Statusendpunkt abgefragt werden?
Meist genügt der Takt der übrigen Verfügbarkeitsprüfungen. Wichtiger als ein sehr kurzer Abstand ist die Wahl der Felder: listen queue zeigt nur den Moment der Abfrage, max listen queue hält dagegen den höchsten Stand seit dem Start des Pools fest und verrät damit auch Spitzen zwischen zwei Abfragen. Zusammen mit dem p95 der Antwortzeit ergibt das ein Bild, in dem auch kurze Engpässe nicht untergehen.
In 60 Sekunden starten

Lassen Sie XICTRAQ Ihre Website bewachen.

Dauerhaft kostenloser Plan verfügbar. Keine Kreditkarte, keine Installation, keine versteckten Kosten.