Gestire le prestazioni
L'ottimizzazione prematura è la radice di tutti i mali.
Forse avrete già letto questa citazione in precedenza, ma vorrei riportarla per intero:
Si dovrebbero tralasciare le micro-ottimizzazioni, diciamo circa il 97% delle volte: l'ottimizzazione prematura è la radice di tutti i mali. Tuttavia, non dovremmo tralasciare l'opportunità di quel 3% critico.
-- Donald Knuth
Anche piccoli miglioramenti delle prestazioni possono fare la differenza, specialmente per i siti di e-commerce. Ora che l'applicazione guestbook è pronta per il debutto, vediamo come possiamo verficarne le prestazioni.
Il modo migliore per scovare quali ottimizzazioni sulle prestazioni potremmo fare è quello di utilizzare un profiler. L'opzione più popolare al giorno d'oggi è Blackfire (disclaimer : sono anche il fondatore del progetto Blackfire).
Introduzione a Blackfire
Blackfire è composto da più parti:
- Un client che attiva i profili (lo strumento CLI di Blackfire o un'estensione del browser per Google Chrome o Firefox);
- Un agent che prepara e aggrega i dati prima di inviarli a blackfire.io per la visualizzazione;
- Un'estensione PHP (detta probe) che fornisce istruzioni al codice PHP.
Per lavorare con Blackfire è necessario iscriversi.
Installare Blackfire sul computer locale eseguendo il seguente script di installazione rapida:
1
$ curl https://installer.blackfire.io/installer.sh | bash
Questo programma di installazione scarica ed installa la CLI di Blackfire.
Una volta fatto, installiamo l'estensione PHP probe su tutte le versioni PHP disponibili:
1
$ sudo blackfire php:install
E attiva l'estensione probe di PHP per il progetto:
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
Riavviare il server web in modo che PHP possa caricare Blackfire:
1 2
$ symfony server:stop
$ symfony server:start -d
La CLI di Blackfire va configurata inserendo le credenziali del client (per memorizzare i profili dei progetti sotto il proprio account). Si trovano nella parte superiore della pagina Settings/Credentials
. Eseguire quindi il seguente comando, sostituendo i segnaposto:
1
$ blackfire client:config --client-id=xxx --client-token=xxx
Impostazione dell'agent di Blackfire su Docker
Il servizio agent di Blackfire è già stato configurato nello stack di Docker Compose:
Per comunicare con il server, è necessario ottenere le credenziali del server (queste credenziali indicano dove si desidera memorizzare i profili e possono essere personalizzate per singolo progetto); si trovano in fondo alla pagina Settings/Credentials
. Memorizzarle in un file locale .env.local
:
1 2 3 4
$ symfony console secrets:set BLACKFIRE_SERVER_ID
# xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
$ symfony console secrets:set BLACKFIRE_SERVER_TOKEN
# xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
A questo punto è possibile lanciare il nuovo container:
1 2
$ docker compose stop
$ docker compose up -d
Sistemare un'installazione di Blackfire non funzionante
Se si riscontra un errore durante la profilazione, aumentare il livello dei log di Blackfire per ottenere maggiori informazioni:
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
Riavviare il server web:
1 2
$ symfony server:stop
$ symfony server:start -d
Ed eseguire un tail sui log:
1
$ symfony server:log
Eseguire nuovamente la profilazione e controllare l'output del log.
Configurazione di Blackfire in produzione
Blackfire è incluso di default in tutti i progetti Platform.sh.
Imposta le credenziali del server come segreti di production:
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
L'estensione PHP probe è già abilitata come ogni altra estensione PHP necessaria:
Configurazione di Varnish per Blackfire
Prima di poter eseguire il deploy per iniziare la profilazione, è necessario un modo per aggirare la cache HTTP di Varnish. In caso contrario, Blackfire non arriverà mai all'applicazione PHP. Autorizzeremo solo le richieste di profilazione provenienti dalla macchina locale.
Trovare il proprio indirizzo IP:
1
$ curl https://ifconfig.me/
E usarlo per configurare Varnish:
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 {
Ora è possibile eseguire il deploy.
Profilazione delle pagine web
È possibile profilare le pagine web tradizionali da Firefox o da Google Chrome tramite le rispettive estensioni dedicate.
Sulla macchina locale, non dimenticare di disabilitare la cache HTTP in config/packages/framework.yaml
durante la profilazione: in caso contrario, verrà profilato il livello di cache HTTP di Symfony invece del proprio codice.
Per ottenere un quadro migliore delle prestazioni della propria applicazione in produzione, si dovrebbe profilare anche l'ambiente "production". Per impostazione predefinita, l'ambiente locale utilizza l'ambiente "development", che aggiunge un overhead significativo (principalmente per raccogliere dati per la barra degli strumenti di debug e il Profiler di Symfony).
Note
Quando profileremo l'ambiente "production", non ci sarà nessuna configurazione da cambiare, visto che abbiamo abilitato il layer di cache HTTP solo per l'ambiente "development" in un capitolo precedente.
Il passaggio dalla macchina locale all'ambiente di produzione può essere fatto cambiando la variabile d'ambiente APP_ENV
nel file .env.local
:
1
APP_ENV=prod
Oppure si può usare il comando server:prod
:
1
$ symfony server:prod
Non dimentichiamo di tornare in dev quando la sessione di profilazione è terminata:
1
$ symfony server:prod --off
Profilazione delle risorse API
La profilazione delle API o della SPA viene fatta in modo migliore sul terminale tramite la CLI di Blackfire, installata in precedenza:
1
$ blackfire curl `symfony var:export SYMFONY_PROJECT_DEFAULT_ROUTE_URL`api
Il comando blackfire curl
accetta esattamente gli stessi parametri e opzioni di cURL.
Confronto delle prestazioni
Nel passo sulla "Cache", abbiamo aggiunto uno strato di cache per migliorare le prestazioni del codice, ma non abbiamo controllato né misurato l'impatto sulle prestazioni di tale modifica. Dato che non siamo molto bravi nell'indovinare cosa sarà veloce e cosa è lento, potremmo ritrovarci in una situazione in cui eseguire qualche ottimizzazione rende l'applicazione più lenta.
Si dovrebbe sempre misurare l'impatto di ogni ottimizzazione, usando un profiler. Blackfire rende il compito visivamente più facile grazie alla sua funzionalità di confronto.
Scrivere test funzionali di tipo Black Box
Abbiamo visto come scrivere test funzionali con Symfony. Blackfire può essere utilizzato per scrivere scenari di navigazione che possono essere eseguiti su richiesta tramite il player di Blackfire. Scriviamo uno scenario che invia un nuovo commento e lo convalida tramite un link via e-mail in sviluppo e tramite un'interfaccia di amministrazione.
Creare un file .blackfire.yaml
con il seguente contenuto:
Scarichiamo il player di Blackfire per poter eseguire lo scenario in locale:
1 2
$ curl -OLsS https://get.blackfire.io/blackfire-player.phar
$ chmod +x blackfire-player.phar
Eseguire questo scenario in sviluppo:
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
1
$ rm blackfire-player.phar
O in produzione:
1
$ ./blackfire-player.phar run --endpoint=`symfony cloud:env:url --pipe --primary` .blackfire.yaml --variable "webmail_url=NONE" --variable="env=prod" -vv
Gli scenari di Blackfire possono anche attivare profili per ogni richiesta ed eseguire test sulle prestazioni aggiungendo l'opzione --blackfire
.
Automatizzare i controlli delle prestazioni
Gestire le prestazioni non significa solo migliorare le prestazioni del codice esistente, ma anche verificare che non vengano introdotte regressioni.
Lo scenario descritto nella sezione precedente può essere eseguito automaticamente, su base regolare, in una attività di CI (Continuous Integration) o in produzione.
Su Platform.sh, consente anche eseguire gli scenari ogni volta che si crea un nuovo branch o si fa un deploy in produzione, per controllare automaticamente le prestazioni del nuovo codice.