Performance-Management
Vorzeitige Optimierung ist die Wurzel allen Übels.
Vielleicht hast Du dieses Zitat schon einmal gelesen. Aber ich würde es gern vollständig zitieren:
Wir sollten die kleinen Effizienzgewinne vergessen, sagen wir in 97% der Fälle: Vorzeitige Optimierung ist die Wurzel allen Übels. Dennoch sollten wir unsere Chancen bei diesen kritischen 3 % nicht verpassen.
-- Donald Knuth
Selbst kleine Performance-Steigerungen können einen Unterschied machen, insbesondere bei E-Commerce-Websites. Nachdem die Gästebuchanwendung nun für die Prime Time bereit ist, lass uns sehen, wie wir ihre Performance überprüfen können.
Der beste Weg, Performance-Optimierungen zu finden, ist die Verwendung eines Profilers. Die beliebteste Option ist heutzutage Blackfire (voller Haftungsausschluss: Ich bin auch der Gründer des Blackfire-Projekts).
Blackfire
Blackfire besteht aus mehreren Teilen:
- Ein Client, der die Analyse auslöst (das Blackfire CLI-Tool oder eine Browsererweiterung für Google Chrome oder Firefox);
- Ein Agent, der Daten aufbereitet und aggregiert, bevor er sie zur Anzeige an blackfire.io sendet;
- Eine PHP-Erweiterung (die Probe), die den PHP-Code instrumentiert.
Um mit Blackfire arbeiten zu können, musst Du Dich zuerst anmelden.
Installiere Blackfire auf Deinem lokalen Computer, indem Du das folgende Schnellinstallationsskript ausführst:
1
$ curl https://installer.blackfire.io/installer.sh | bash
Dieser Installer lädt das Blackfire CLI Tool herunter und installiert es.
Wenn das getan ist, installiere die PHP-Probe bei allen verfügbaren PHP-Versionen:
1
$ sudo blackfire php:install
Und aktiviere die PHP-Probe für unser Projekt:
1 2 3 4 5 6 7 8 9 10
--- a/php.ini
+++ b/php.ini
@@ -6,3 +6,7 @@ session.use_strict_mode=On
realpath_cache_ttl=3600
zend.detect_unicode=Off
xdebug.file_link_format=vscode://file/%f:%l
+
+[blackfire]
+# use php_blackfire.dll on Windows
+extension=blackfire.so
Starte den Webserver neu, damit PHP Blackfire laden kann:
1 2
$ symfony server:stop
$ symfony server:start -d
Das Blackfire CLI Tool muss mit Deinen persönlichen Client-Credentials konfiguriert werden (um Deine Projektanalyse unter Deinem persönlichen Konto zu speichern). Du findest sie oben auf der Settings/Credentials
Seite. Führe den folgenden Befehl aus, indem Du die Platzhalter ersetzt:
1
$ blackfire client:config --client-id=xxx --client-token=xxx
Den Blackfire-Agenten in Docker einrichten
Der Blackfire-Agent-Dienst wurde bereits im Docker-Compose-Stack konfiguriert:
Um mit dem Server zu kommunizieren, benötigst Du Deine persönlichen Server-Credentials (diese identifizieren, wo Du Deine Analysen speichern möchtest – Du kannst pro Projekt eines erstellen); Du findest sie am Ende der Settings/Credentials
-`Seite`_. Speichere sie in einer lokalen .env.local
-Datei:
1 2 3 4
$ symfony console secrets:set BLACKFIRE_SERVER_ID
# xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
$ symfony console secrets:set BLACKFIRE_SERVER_TOKEN
# xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Du kannst nun den neuen Container starten:
1 2
$ docker compose stop
$ docker compose up -d
Eine nicht funktionierende Blackfire-Installation reparieren
Wenn Du beim Analysieren einen Fehler erhälst, erhöhe das Blackfire-Log-Level, um weitere Informationen in den Logs zu erhalten:
1 2 3 4 5 6 7
--- a/php.ini
+++ b/php.ini
@@ -10,3 +10,4 @@ zend.detect_unicode=Off
[blackfire]
# use php_blackfire.dll on Windows
extension=blackfire.so
+blackfire.log_level=4
Starte den Webserver neu:
1 2
$ symfony server:stop
$ symfony server:start -d
Und lass dir die Logs ausgeben:
1
$ symfony server:log
Analysiere erneut und überprüfe die Log-Ausgabe.
Blackfire auf dem Produktivsystem konfigurieren
Blackfire ist standardmäßig in allen Platform.sh-Projekten enthalten.
Erstelle die Server-Zugangsdaten als production-Geheimnisse:
1 2 3 4
$ symfony console secrets:set BLACKFIRE_SERVER_ID --env=prod
# xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
$ symfony console secrets:set BLACKFIRE_SERVER_TOKEN --env=prod
# xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Die PHP-Probe ist bereits aktiviert, genauso wie andere notwendige PHP-Erweiterungen:
Varnish für Blackfire konfigurieren
Bevor Du deployst um Blackfire nutzen zu können, benötigst Du eine Möglichkeit, den Varnish HTTP-Cache zu umgehen. Wenn nicht, wird Blackfire nie direkt auf die PHP-Anwendung zugreifen. Du wirst nur autorisierte Anfragen analysieren, die von deinem lokalen Rechner kommen.
Finde Deine aktuelle IP-Adresse heraus:
1
$ curl https://ifconfig.me/
Und verwende sie, um Varnish zu konfigurieren:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
--- a/.platform/config.vcl
+++ b/.platform/config.vcl
@@ -1,3 +1,11 @@
+acl profile {
+ # Authorize the local IP address (replace with the IP found above)
+ "192.168.0.1";
+ # Authorize Blackfire servers
+ "46.51.168.2";
+ "54.75.240.245";
+}
+
sub vcl_recv {
set req.backend_hint = application.backend();
set req.http.Surrogate-Capability = "abc=ESI/1.0";
@@ -8,6 +16,16 @@ sub vcl_recv {
}
return (purge);
}
+
+ # Don't profile ESI requests
+ if (req.esi_level > 0) {
+ unset req.http.X-Blackfire-Query;
+ }
+
+ # Bypass Varnish when the profile request comes from a known IP
+ if (req.http.X-Blackfire-Query && client.ip ~ profile) {
+ return (pass);
+ }
}
sub vcl_backend_response {
Nun kannst Du deployen.
Webseiten analysieren
Du kannst traditionelle Webseiten in Firefox oder Google Chrome über die entsprechenden Erweiterungen analysieren.
Vergiss nicht, den HTTP-Cache auf Deinem lokalen Rechner in config/packages/framework.yaml
beim Analysieren zu deaktivieren: Wenn nicht, wirst Du den Symfony HTTP-Cache-Layer anstelle Deines eigenen Codes analysieren.
Um Dir ein besseres Bild von der Performance Deiner Anwendung auf dem Produktivsystem zu machen, solltest Du auch die "Production"-Environment analysieren. Standardmäßig verwendet Deine lokale Environment die "Development"-Environment, die eine Menge Extras mit sich bringt (hauptsächlich um Daten für die Web-Debug-Toolbar und den Symfony-Profiler zu sammeln).
Note
Da wir das Produktivsystem analysieren, brauchen wir keine Konfiguration ändern, weil wir den Symfony HTTP-Cache-Layer nur für die Entwicklungsumgebung im vorherigen Kapitel aktiviert haben.
Die Umstellung Deiner lokalen Maschine auf die Produktivumgebung kann durch Ändern der Environment-Variable APP_ENV
in der .env.local
-Datei erfolgen:
1
APP_ENV=prod
Oder du kannst den server:prod
-Befehl verwenden:
1
$ symfony server:prod
Vergiss nicht, wieder auf dev umzustellen, wenn deine Analyse-Sitzung endet:
1
$ symfony server:prod --off
API-Ressourcen analysieren
Die Analyse der API oder der SPA erfolgt besser in der CLI über das Blackfire CLI Tool, das Du zuvor installiert hast:
1
$ blackfire curl `symfony var:export SYMFONY_PROJECT_DEFAULT_ROUTE_URL`api
Der blackfire curl
-Befehl akzeptiert genau die gleichen Argumente und Optionen wie cURL.
Performancevergleich
Im Schritt über "Cache" haben wir eine Cache-Ebene hinzugefügt, um die Performance unseres Codes zu verbessern, aber wir haben die Auswirkungen der Änderung auf die Performance weder überprüft noch gemessen. Da wir alle sehr schlecht darin sind, zu erraten, was schnell und was langsam ist, kannst Du in eine Situation geraten, in der eine Optimierung Deine Anwendung tatsächlich langsamer macht.
Du solltest immer die Auswirkungen jeder Optimierung, die Du durchführst, analysieren. Blackfire macht dies dank seiner Vergleichsfunktion optisch einfacher.
Funktionale Black-Box-Tests schreiben
Wir haben gesehen, wie man mit Symfony funktionale Tests schreibt. Mit Blackfire kann man Browser-Szenarien schreiben, die bei Bedarf über den Blackfire-Player ausgeführt werden können. Schreiben wir ein Szenario, das einen neuen Kommentar einreicht und ihn über den E-Mail-Link in DEV und übers Admin-Backend auf dem Produktivsystem validiert.
Erstelle eine .blackfire.yaml
Datei mit folgendem Inhalt:
Lade den Blackfire-Player herunter, um das Szenario lokal ausführen zu können:
1 2
$ curl -OLsS https://get.blackfire.io/blackfire-player.phar
$ chmod +x blackfire-player.phar
Führe dieses Szenario in DEV aus:
1
$ ./blackfire-player.phar run --endpoint=`symfony var:export SYMFONY_PROJECT_DEFAULT_ROUTE_URL` .blackfire.yaml --variable "webmail_url=`symfony var:export MAILER_WEB_URL 2>/dev/null`" --variable="env=dev" -vv
Oder in PROD:
1
$ ./blackfire-player.phar run --endpoint=`symfony cloud:env:url --pipe --primary` .blackfire.yaml --variable "webmail_url=NONE" --variable="env=prod" -vv
Blackfire-Szenarien können auch Analysen für jeden Request auslösen und Performance-Tests durchführen, indem Du das --blackfire
Flag hinzufügst.
Performance-Tests automatisieren
Beim Performance-Management geht es nicht nur darum, die Performance des vorhandenen Codes zu verbessern, sondern auch darum, sicherzustellen, dass keine Performanceregressionen eingeführt werden.
Das im vorherigen Abschnitt beschriebene Szenario kann automatisch in einem Continuous Integration-Workflow oder regelmäßig auf dem Produktivsystem ausgeführt werden.
Bei Platform.sh können die Szenarien ausgeführt werden, wenn Du einen neuen Branch erstellst oder zum Produktivsystem deployst, um die Performance des neuen Codes automatisch zu überprüfen.