PHP-Entwickler in Düsseldorf

PHP-Entwickler für Unternehmen in Düsseldorf: eine langsame PHP-Anwendung erst messen (Xdebug, SPX), dann OPcache, JIT, PHP-FPM, Datenbankabfragen und Caches gezielt einstellen. Schriftlich, remote, kostenlose erste Einschätzung.

PHP-Entwickler

Mein Platz in der WordPress-Community

  • Mein wordpress.org-Konto besteht seit 2006.
  • Ich habe zum WordPress-Core in den Versionen 7.0 und 7.1 beigetragen.
  • Ich betreue 30 Plugins auf wordpress.org.
  • Ich organisiere WordCamps und trete dort als Speaker auf.
  • Ich war bei jedem WordCamp Europe von 2017 bis 2026 dabei.
  • Lokales WordPress-Meetup: WordPress Düsseldorf Meetup

Mein WordPress.org-Profil

Eine PHP-Anwendung wird selten wegen einer einzelnen Einstellung langsam. Meist summieren sich viele kleine Ursachen: zu viele Datenbankabfragen, ein falsch dimensionierter Prozess-Pool, ein Cache, der bei jedem Release geleert wird. Dieser Text zeigt die Reihenfolge, in der ich eine langsame Anwendung untersuche, und sagt bei jeder Stellschraube, was die offizielle Dokumentation dazu festhält. Mein Name ist Mariusz Szatkowski, ich entwickle allein von Gdynia aus. Ich arbeite seit 2006 mit WordPress, remote und schriftlich, ohne Termine und Anrufe.

#Was Unternehmen in Düsseldorf von einer schnellen Anwendung haben

Die Landeshauptstadt beschreibt sich auf ihrer Seite zu Wirtschaft und Standort als Sitz von Unternehmen aus Industrie, Handel und Dienstleistungen und nennt die Kommunikations-, Werbe- und Modebranche. Die Wirtschaftsförderung Düsseldorf führt auf ihrer Standortseite 41.526 Unternehmen mit Sitz in der Stadt (Abruf am 11.11.2026). Für Betreiber von Shops, Kundenportalen und Kampagnenseiten heißt das: Ihr PHP-System muss Lastspitzen durch Aktionen und Newsletter aushalten, und eine langsame Seite fällt zuerst dort auf, wo Besucher bestellen oder sich anmelden.

Bei Core Web Vitals gelten die offiziellen Schwellen von web.dev: LCP bis 2,5 s, INP bis 200 ms, CLS bis 0,1. Die Serverseite entscheidet vor allem über den LCP, weil der Browser erst mit der ersten Antwort Ihres PHP-Systems beginnen kann.

Landtag Nordrhein-Westfalen am Rheinufer in Düsseldorf

Foto: Mstyslav Chernov, CC BY-SA 4.0, Wikimedia Commons.

#Erst messen: Profil mit Xdebug oder SPX

Ich ändere keine Einstellung, bevor ich weiß, wo die Zeit bleibt. Dafür gibt es zwei verbreitete Werkzeuge.

Xdebug. Laut Profiler-Dokumentation setzen Sie xdebug.mode auf profile. Xdebug schreibt dann Dateien, deren Name mit cachegrind.out. beginnt, in das Verzeichnis aus xdebug.output_dir. Die Dokumentation warnt, dass diese Dateien bei komplexen Skripten sehr groß werden können. Mit xdebug.start_with_request=trigger läuft das Profil nur, wenn die Variable XDEBUG_TRIGGER als Umgebungswert, GET/POST-Parameter oder Cookie gesetzt ist. Geöffnet werden die Dateien etwa mit KCacheGrind: Die Spalte “Self” zeigt die Zeit in der Funktion selbst, die inklusive Aufrufen die Gesamtzeit. Auf der Installationsseite steht außerdem: Der Modus off lässt Xdebug nichts tun außer zu prüfen, ob eine Funktion aktiv ist, und eignet sich, wenn Sie nahezu keinen Overhead wollen.

; php.ini der Staging-Umgebung, nicht der Produktion
xdebug.mode = profile
xdebug.start_with_request = trigger
xdebug.output_dir = /var/tmp/xdebug

SPX. Die README von SPX beschreibt eine Web-Oberfläche mit Zeitleiste, Flat Profile und Flamegraph. Sie nennt das Projekt experimentell und ausdrücklich nur für Nicht-Produktivumgebungen sicher. Wer das Web-Interface erreicht, könnte sensible Informationen über die Anwendung lesen oder mit aufwendigen Profilen eine Überlast auslösen. Deshalb verlangt SPX zwei Sperren: eine IP-Whitelist (spx.http_ip_whitelist) und einen geheimen Schlüssel (spx.http_key). Hinter einem Reverse-Proxy muss spx.http_ip_var angepasst werden.

Für beide Werkzeuge gilt: Ich profiliere eine Kopie mit anonymisierten Daten, nicht die Produktion. Welche Seiten ich messe, halte ich nach Absprache mit Ihnen schriftlich fest: die langsamsten Seiten aus Ihren Nutzerberichten, nicht die, die mir zuerst einfallen.

#OPcache: Speicher, Zeitstempel und Deployment

OPcache hält den kompilierten Code im Arbeitsspeicher, damit PHP Dateien nicht bei jeder Anfrage neu übersetzt. Das PHP-Handbuch nennt als Standardwerte unter anderem opcache.memory_consumption=128 (Megabyte), opcache.interned_strings_buffer=8 und opcache.max_accelerated_files=10000. Der letzte Wert wird auf die nächste Primzahl aus einer festen Liste aufgerundet. Ein größeres Projekt mit vielen Composer-Paketen kann diese Grenze überschreiten. Ob das bei Ihnen so ist, zeigt opcache_get_status(), nicht eine Faustregel.

Zwei Punkte entscheiden im Alltag:

  • opcache.validate_timestamps. Ist der Wert aktiv, prüft OPcache alle opcache.revalidate_freq Sekunden, ob sich eine Datei geändert hat. Wird er abgeschaltet, müssen Sie laut Handbuch opcache_reset() oder opcache_invalidate() aufrufen oder den Webserver neu starten, damit Änderungen wirken. Das passt zu einem Deployment, das ohnehin einen definierten Schritt nach dem Release hat. Es passt nicht zu einem Server, auf dem jemand per FTP einzelne Dateien ändert.
  • opcache.enable_cli. Der Standard ist 0. Für Queue-Worker oder Cron-Skripte auf der Kommandozeile gilt OPcache also nur, wenn Sie ihn dort ausdrücklich einschalten.

#Preloading: wann es sich lohnt

Seit PHP 7.4.0 kann PHP beim Start des Prozesses Dateien in OPcache laden. Das Handbuch beschreibt den Kompromiss: Der Code steht allen Anfragen ohne Einbinden zur Verfügung, dafür steigt der Grundbedarf an Speicher. Zum Leeren ist ein Neustart des PHP-Prozesses nötig, deshalb ist die Funktion laut Dokumentation nur in der Produktion praktikabel, nicht in der Entwicklung. “Alles vorladen” sei zwar die einfachste Strategie, aber nicht unbedingt die beste.

opcache.preload = /var/www/app/preload.php

Das Skript preload.php läuft einmal beim Serverstart. Es bindet Dateien mit require_once oder opcache_compile_file() ein. Die Dokumentation erklärt den Unterschied: include führt den Code aus, opcache_compile_file() nicht, und Letzteres lädt Dateien in beliebiger Reihenfolge. Konstanten werden nicht vorgeladen.

Ob Preloading messbar etwas bringt, beantwortet nur ein Vorher-Nachher-Vergleich in Ihrer Umgebung.

#JIT: wann er hilft und wann nicht

Der JIT-Compiler ist Teil von OPcache. Laut Handbuch ist opcache.jit ab PHP 8.4.0 standardmäßig disable, davor war es tracing. Der Wert tracing (auch on) ist für die meisten Nutzer empfohlen. Der Puffer opcache.jit_buffer_size hat ab PHP 8.4.0 den Standard 64M, davor 0, und mit 0 ist der JIT aus. Der Speicher für den Puffer kommt zusätzlich zu opcache.memory_consumption.

Ob er Ihrer Anwendung hilft, hängt vom Profil ab. Der JIT-RFC erwartet Vorteile bei rechenintensiven Aufgaben und stellt fest, dass reale Anwendungen wie WordPress nicht deutlich profitieren. Auf der Release-Seite zu PHP 8.0 steht dazu: Typische Anwendungsleistung sei auf dem Niveau von PHP 7.4. Eine Seite, die ihre Zeit mit Datenbank und Netzwerk verbringt, wird durch JIT nicht schneller. Eine Anwendung mit Bildberechnung, Preisregeln in langen Schleifen oder Parsern kann es sein. Das Profil aus dem ersten Schritt zeigt, in welche Gruppe Ihre Anwendung gehört.

#PHP-FPM: Prozessmanager und Pool-Größe

Die FPM-Konfiguration kennt drei Prozessmanager:

WertVerhalten laut Dokumentation
staticfeste Zahl von Kindprozessen (pm.max_children)
dynamicZahl richtet sich nach pm.max_children, pm.start_servers, pm.min_spare_servers, pm.max_spare_servers
ondemandProzesse starten bei Bedarf, ungenutzte beendet pm.process_idle_timeout (Standard 10 s)

pm.max_children begrenzt die gleichzeitig bearbeiteten Anfragen. Setzen Sie ihn zu niedrig, warten Besucher in der Schlange, auch wenn der Server Reserven hat. Setzen Sie ihn zu hoch, gehen dem Server bei Lastspitzen der Arbeitsspeicher und damit die Antwortfähigkeit aus. Die richtige Zahl ergibt sich aus dem gemessenen Speicherbedarf eines Workers und dem verfügbaren RAM des Servers, nicht aus einem Wert von einer anderen Installation.

Drei weitere Einstellungen helfen beim Diagnostizieren:

  • pm.status_path liefert eine Statusseite mit Zählern zum Pool. Ohne diese Einstellung ist sie nicht erreichbar.
  • request_slowlog_timeout und slowlog schreiben bei langsamen Anfragen einen PHP-Backtrace in eine Datei. Der Standard ist 0, also aus.
  • pm.max_requests startet einen Worker nach einer festen Anfragenzahl neu und hilft laut Dokumentation gegen Speicherlecks in Bibliotheken von Drittanbietern.

#Datenbank: Abfragen zählen und N+1 beseitigen

Wenn das Profil zeigt, dass die Zeit in der Datenbank liegt, zähle ich zuerst, wie viele Abfragen eine Seite auslöst. Ein typisches Muster ist N+1: Eine Abfrage lädt eine Liste, und für jedes Element folgt eine weitere Abfrage für verknüpfte Daten. Die Dokumentation zu Eloquent-Beziehungen in Laravel behandelt das ausführlich und empfiehlt Eager Loading mit with(). Sie weist auch darauf hin, dass N+1 trotz Eager Loading wieder auftreten kann, wenn Sie in einer Schleife vom Kind auf das Elternmodell zugreifen.

// AppServiceProvider::boot(), laut Laravel-Dokumentation
Model::preventLazyLoading(! $this->app->isProduction());

Damit wirft Laravel in Entwicklung und Test eine Ausnahme, sobald eine Beziehung nachgeladen wird. In der Produktion läuft die Anwendung weiter. In Symfony-Projekten mit Doctrine gehe ich genauso vor: Abfragen im Profiler zählen, Fetch-Joins prüfen. Fehlende Indizes erkenne ich am Abfrageplan der Datenbank selbst. Ich nenne hier bewusst keine Zahl, ab der eine Seite “zu viele” Abfragen hat. Das hängt vom Projekt ab.

#Caches: APCu und Redis

Ein Cache kommt bei mir nach dem Messen und nach der Abfragen-Bereinigung. Zwei Varianten setze ich am häufigsten ein.

APCu ist laut Handbuch ein Schlüssel-Wert-Speicher im Arbeitsspeicher für PHP-Variablen. Die Größe steuert apc.shm_size (Standard 32M). Die mitgelieferte Datei apc.php zeigt unter anderem, wie oft der Cache voll war. Läuft der Cache ständig voll und muss geleert werden, schadet das laut Handbuch der Skriptleistung; die Zahl der Räumungen soll in einem gut eingestellten Cache klein bleiben. Für die Kommandozeile ist APCu standardmäßig aus (apc.enable_cli=0).

Redis ist ein eigener Serverprozess. Das ist der Vorteil, wenn mehrere Webserver denselben Cache nutzen sollen, und der Preis, weil jeder Zugriff über das Netzwerk geht. Die Redis-Dokumentation zur Eviction beschreibt, dass Redis häufig als Cache vor einem langsameren Server oder einer Datenbank dient und bei Erreichen des Speicherlimits (maxmemory) nach einer gewählten Richtlinie Schlüssel entfernt. Einen Cache ohne Speicherlimit und ohne Ablaufzeit betreibe ich nicht.

Für beide gilt: Jeder Cache braucht eine Regel, wann Einträge ungültig werden. Enthalten Einträge personenbezogene Daten, brauchen sie außerdem eine Löschregel. Für Nordrhein-Westfalen ist die Datenschutzaufsicht die LDI NRW. Das spreche ich vor dem Einbau schriftlich mit Ihnen durch.

#Reihenfolge und Checkliste

SchrittFrageWo ich nachsehe
1Welche Seiten sind langsam, wann?Ihre Beobachtung, Server-Log
2Wo bleibt die Zeit?Xdebug- oder SPX-Profil auf Staging
3Läuft OPcache und passt der Speicher?opcache_get_status()
4Warten Anfragen auf freie Worker?FPM-Statusseite, Slowlog
5Wie viele Abfragen hat die Seite?Profil, Abfrage-Log
6Hilft ein Cache, und wie läuft er ab?Messung vor und nach dem Einbau
7Hilft JIT?Nur bei rechenlastigem Profil, mit Messung

Nach jedem Schritt messe ich erneut. Bleibt eine Änderung ohne Wirkung, nehme ich sie zurück, statt sie zu behalten.

#So läuft ein Auftrag mit mir

Sie schicken mir Beschreibung und Zugang zu einer Staging-Kopie. Ich stelle schriftlich Rückfragen und halte Umfang und Annahmen fest, bevor ich beginne. Änderungen gehen zuerst auf Staging, Sie nehmen sie ab, dann übertrage ich sie. Ein Bericht beschreibt, was gemessen und was geändert wurde. Wer die Anwendung danach weiter betreut, entscheiden Sie: Auf Wunsch übernehme ich Wartung, siehe Wartung und Support in Düsseldorf. Wer mich für größere PHP-Projekte sucht, findet die Übersicht auf der Seite PHP-Entwickler. Bei Änderungen an der Oberfläche kommt das Layout von Ihnen, ich setze es um.

Von Ihnen brauche ich: die Adresse der Anwendung, die PHP-Version, die Hosting-Art (eigener Server, Managed Hosting, Container), Zugriff auf Konfiguration und Logs und eine Liste der Seiten, die Ihre Nutzer als langsam melden.

#Häufige Fragen

#Bringt mir die JIT-Einstellung eine schnellere Anwendung?

Nicht automatisch. Der JIT-RFC im PHP-Wiki sagt selbst, dass die JIT bei rechenintensiven Aufgaben hilft, aber reale Anwendungen wie WordPress nicht deutlich beschleunigt. Ich schalte sie erst nach einer Messung an, und nur für Code, der überwiegend rechnet statt auf Datenbank und Netzwerk zu warten.

#Darf ich opcache.validate_timestamps abschalten?

Ja, wenn Ihr Deployment danach OPcache zurücksetzt. Das PHP-Handbuch nennt opcache_reset(), opcache_invalidate() oder einen Neustart des Webservers. Ohne diesen Schritt läuft nach einem Release alter Code weiter.

#Welchen Prozessmanager soll PHP-FPM nutzen?

Das hängt vom Lastbild und vom Arbeitsspeicher ab. Die Dokumentation beschreibt static, dynamic und ondemand. Ich lese zuerst die Auslastung aus der FPM-Statusseite und dem Speicherbedarf eines Workers, bevor ich pm.max_children festlege.

#Reicht ein Cache, wenn die Seite langsam ist?

Er versteckt das Problem, löst es aber nicht. Wenn ein Profil Hunderte gleichartiger Abfragen pro Seite zeigt, ist der Cache nur ein Pflaster. Ich zähle zuerst die Abfragen, beseitige N+1 und setze Caches danach dort ein, wo Daten sich selten ändern.

#Darf ich auf dem Live-Server profilieren?

Ich bevorzuge eine Kopie oder die Staging-Umgebung. Die SPX-README nennt das Profil-Interface ein Sicherheitsrisiko, solange es nicht durch IP-Whitelist und Schlüssel geschützt ist. Xdebug schreibt im Profilmodus große Dateien und startet auf Wunsch nur bei einem Trigger.

#Wie fange ich an?

Schreiben Sie mir über das Kontaktformular: die Adresse Ihrer Anwendung, was langsam ist und wann, Ihre PHP-Version und den Hosting-Stand. Ich antworte schriftlich an Werktagen. Die erste schriftliche Einschätzung zu Umfang und Vorgehen ist kostenlos.

#Schreiben Sie mir

Wenn Ihre PHP-Anwendung in Düsseldorf oder anderswo zu langsam ist, schicken Sie mir die Adresse, das Symptom und Ihren Termin. Ich sehe mir an, was sich messen lässt, und sage Ihnen schriftlich, welche Schritte ich vorschlage und welche nicht. Nutzen Sie dafür das Kontaktformular.

Brauchen Sie die Leistung: PHP-Entwickler in Düsseldorf?

Beschreiben Sie Ihr Projekt per E-Mail. Antwort innerhalb von 48 Stunden.

Projekt beschreiben

Weitere WordPress-Dienste und Wissensbasis entdecken