PHP-Performance
Schnelles PHP wird eingestellt, nicht gekauft.
Unser Team arbeitet seit fünfundzwanzig Jahren mit PHP und weiß, wo eine Anfrage ihre Zeit verliert. Wir finden sie auf Ihrem Server und holen sie zurück, Schicht für Schicht.
Anatomie einer Anfrage
Eine Seite ist eine Kette von Wartezeiten: den Server finden, die Verbindung öffnen, auf PHP warten, kompilieren, ausführen, die Datenbank fragen, senden. Wechseln Sie zwischen den Zuständen und sehen Sie, welche Glieder wir verkürzen.
-
DNS-Abfrage Beantwortet vom Resolver des Besuchers. In jedem Zustand gleich: Dieser Teil ist das Netzwerk des Besuchers. In jedem Zustand gleich: Dieser Teil ist das Netzwerk des Besuchers.
-
Verbindung und TLS Eine ältere TLS-Einrichtung, eine neue Verbindung für jede Datei. TLS 1.3 und eine HTTP/2-Verbindung, die für jede Datei wiederverwendet wird. TLS 1.3 und eine HTTP/2-Verbindung, die für jede Datei wiederverwendet wird.
-
Warten auf einen PHP-Worker Alle Worker sind beschäftigt, also wartet die Anfrage in der Schlange. Ein nach dem Speicher bemessener Pool: Ein freier Worker ist bereit. Kein PHP-Worker wird gebraucht.
-
Kompilieren der Skripte PHP liest und kompiliert jede Datei bei jeder Anfrage. OPcache liefert die kompilierten Skripte aus dem Speicher. Nichts zu kompilieren.
-
Dateien und Klassen finden Der Autoloader durchsucht für jede Klasse Verzeichnisse. Ein Classmap-Autoloader und ein gefüllter Realpath-Cache. Nichts zu laden.
-
Ihr Code läuft Die eigentliche Arbeit der Anwendung. Weitgehend gleich: Der JIT ändert das bei einer typischen Website selten. Ihr Code läuft für diesen Besuch nicht.
-
Datenbankabfragen Fehlende Indizes und dieselbe Abfrage auf jeder Seite. Indizes ergänzt, wiederholte Antworten in Redis gehalten. Keine Abfrage wird gesendet.
-
Senden der Seite Unkomprimiert gesendet. Komprimiert, bevor sie den Server verlässt. Die fertige Seite, direkt aus dem Seiten-Cache.
Die Balken oben sind eine Zeichnung. Diese Zahl ist eine Messung.
Der Rest der Zeit ist die Entfernung zwischen unseren Servern in Deutschland und Ihnen. Dieser Teil hängt von Ihrem Standort ab, also messen Sie ihn über Ihre eigene Verbindung.
Über Ihre Verbindung messenDie Einstellungen, die das meiste Warten beseitigen
Kompilieren, Dateien suchen und Klassen laden geschieht, bevor Ihr Code eine einzige Zeile ausführt. Mit diesen Einstellungen geschieht es einmal statt bei jeder Anfrage.
opcache.enable=1
opcache.memory_consumption=256
opcache.interned_strings_buffer=16
opcache.max_accelerated_files=20000
opcache.validate_timestamps=0
opcache.preload=/srv/app/preload.php
opcache.preload_user=www-data
opcache.jit=tracing
opcache.jit_buffer_size=64M
realpath_cache_size=4096K
realpath_cache_ttl=600
$ composer install --no-dev --classmap-authoritative
-
OPcache
PHP kompiliert jede Datei, bevor es sie ausführt. OPcache hält das kompilierte Ergebnis im gemeinsamen Speicher, sodass die nächste Anfrage diese Arbeit überspringt. Wir bemessen Speicher und Dateianzahl nach der Website und prüfen an der Trefferquote, dass nichts verdrängt wird.
Im Produktivbetrieb prüft PHP nicht mehr jede Datei auf Änderungen; jedes Deployment leert den Cache selbst.
-
Preloading
Bei einem Framework lädt Preloading dessen Kerndateien einmal beim Start von PHP und hält sie für jede Anfrage bereit. Eine Änderung an diesen Dateien erfordert einen Neustart, deshalb gehört der Neustart zum Deployment.
-
JIT
Der JIT übersetzt häufig ausgeführten PHP-Code in Maschinencode. Er hilft bei Arbeit, die den Prozessor beschäftigt - Bildverarbeitung, Berechnungen, lange Schleifen. Eine typische Website verbringt ihre Zeit mit Warten auf Datenbank und Netzwerk, und dort ändert der JIT wenig. Wir schalten ihn dort ein, wo eine Messung einen Unterschied zeigt, nicht überall.
-
Realpath-Cache
Jedes include fragt das Dateisystem, wo eine Datei wirklich liegt. Ein größerer Realpath-Cache hält diese Antworten im Speicher - wichtig für Frameworks, die Hunderte Dateien pro Anfrage laden.
-
Composer-Autoloader
Eine verbindliche Classmap findet jede Klasse mit einem einzigen Nachschlagen, statt Verzeichnisse zu durchsuchen, und die Entwicklungspakete bleiben vom Server fern.
Der Stellregler: PHP-FPM
PHP-FPM hält einen Pool von PHP-Workern bereit. Zu wenige, und Anfragen stauen sich; zu viele, und dem Server geht der Speicher aus und er wird für alle langsamer. Der Pool richtet sich nach dem, was der Server tatsächlich hat.
pm = static
pm.max_children = 64
Eine feste Zahl von Workern, immer aktiv
Für einen Server, der einer stark besuchten Website gehört. Es wird keine Zeit mit dem Starten von Prozessen verbracht, und der Speicherbedarf ist im Voraus bekannt.
pm = dynamic
pm.max_children = 64
pm.start_servers = 8
pm.min_spare_servers = 4
pm.max_spare_servers = 12
Einige Worker bereit, mehr unter Last
Hält einige freie Worker in Bereitschaft und startet mehr, wenn der Verkehr steigt, bis zur Grenze. Die übliche Wahl für eine Website mit täglichen Spitzen.
pm = ondemand
pm.max_children = 64
pm.process_idle_timeout = 10s
Worker nur, wenn eine Anfrage kommt
Für viele kleine Websites auf einem Server: Der Speicher geht an die Websites, die gerade besucht werden, und die erste Anfrage nach einer ruhigen Phase zahlt einen kurzen Start.
Wie wir pm.max_children festlegen
pm.max_children = Speicher für PHP ÷ Speicher pro Worker
$ ps --no-headers -o rss -C php-fpm8.3 | awk '{s+=$1} END {print s/NR/1024 " MB"}'
Ein Rechenbeispiel, keine Empfehlung: Die echten Zahlen kommen von Ihrem Server, und wir lassen Reserve für die Spitze.
- pm.max_requests
- Ersetzt einen Worker nach einer festen Zahl von Anfragen, damit ein schleichendes Speicherleck nie zum Ausfall wird.
- request_slowlog_timeout
- Eine Anfrage, die länger läuft, schreibt ihren Stack-Trace in das Slow-Log, das die zu prüfende Funktion nennt.
- request_terminate_timeout
- Beendet eine außer Kontrolle geratene Anfrage, bevor sie einen Worker dauerhaft blockiert.
- pm.status_path
- Zeigt die Warteschlange und wie oft der Pool an seine Grenze stieß - die erste Stelle, an der wir nachsehen, wenn eine Website zur Spitzenzeit langsam wird.
Zwei Wege vom Webserver zu PHP
Wir betreiben beide und wählen danach, was die Website braucht. So oder so ist die schnellste Anfrage die, die PHP nie beantworten muss.
LiteSpeed + LSAPI
- Besucher
- LiteSpeed
- LSCacheSeiten-Cache
- LSAPI
- lsphp
LiteSpeed spricht über sein eigenes LSAPI-Protokoll mit PHP und hält ganze Seiten in LSCache, den WordPress und andere Anwendungen genau dann leeren können, wenn sich Inhalte ändern.
Nginx + PHP-FPM
- Besucher
- Nginx
- fastcgi_cacheSeiten-Cache
- FastCGI
- PHP-FPM
Nginx liefert statische Dateien selbst aus, reicht PHP über einen lokalen Socket an einen PHP-FPM-Pool weiter und kann fertige Seiten für nicht angemeldete Besucher im FastCGI-Cache halten.
-
Redis für Objekte und Sessions
Die Antworten, die eine Seite immer wieder bei der Datenbank erfragt, bleiben im Speicher, und Sessions berühren die Festplatte nicht mehr.
-
Ein Ganzseiten-Cache
Ein nicht angemeldeter Besucher erhält eine fertige Seite, ohne dass PHP oder die Datenbank überhaupt gefragt werden. Warenkörbe, Konten und Kassen bleiben außen vor.
-
HTTP/2 und Kompression
Eine verschlüsselte Verbindung trägt jede Datei der Seite, Text wird vor dem Versand komprimiert, und statische Dateien erhalten lange Cache-Laufzeiten mit versionierten Namen.
-
Zeit in der Datenbank
Das Slow-Query-Log und EXPLAIN zeigen, welche Abfrage wartet und warum; meist macht ein Index oder eine wiederholte Abfrage den Großteil aus.
Wie wir Datenbanken optimieren
Erst messen wir, dann ändern wir eine Sache
Jede Änderung erfolgt gegen eine Messung davor, damit wir Ihnen zeigen können, was sie bewirkt hat. Das sind die Messwerte.
opcache_get_status()Trefferquote, freier Speicher und ob Skripte verdrängt werden.pm.status_pathDie Warteschlange und wie oft der Pool seine Grenze erreichte.slowlogDer Stack-Trace jeder Anfrage, die zu lange lief.slow_query_log + EXPLAINWelche Abfragen warten, wie viele Zeilen sie lesen und welcher Index fehlt.redis-cli INFO statsCache-Treffer gegen Fehlgriffe und ob Schlüssel verdrängt werden.curl -w %{time_starttransfer}Die Zeit bis zum ersten Byte, vorher und nachher auf dieselbe Weise gemessen.
Sie möchten die andere Hälfte der Zahl - die Entfernung von unseren Servern zu Ihnen? Geschwindigkeitstest starten

Sagen Sie uns, welche Seite langsam ist
Schicken Sie uns die Adresse und wo sie heute läuft. Wir sehen uns zuerst den Server an, sagen Ihnen dann, was wir ändern würden und was es bewirken sollte - und erstellen nach diesem Gespräch ein Angebot.