Skip to content
  • About
    • What is Symfony?
    • Community
    • News
    • Contributing
    • Support
  • Documentation
    • Symfony Docs
    • Symfony Book
    • Screencasts
    • Symfony Bundles
    • Symfony Cloud
    • Training
  • Services
    • Platform.sh for Symfony Best platform to deploy Symfony apps
    • SymfonyInsight Automatic quality checks for your apps
    • Symfony Certification Prove your knowledge and boost your career
    • SensioLabs Professional services to help you with Symfony
    • Blackfire Profile and monitor performance of your apps
  • Other
  • Blog
  • Download
sponsored by
  1. Home
  2. Documentation
  3. Symfony: The Fast Track
  4. Italian
  5. Gestire le prestazioni

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
@@ -7,3 +7,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:

docker-compose.override.yml
1
2
3
4
5
6
7
8
9
###> blackfireio/blackfire-symfony-meta ###
blackfire:
    image: blackfire/blackfire:2
    # uncomment to store Blackfire credentials in a local .env.local file
    #env_file: .env.local
    environment:
    BLACKFIRE_LOG_LEVEL: 4
    ports: [8307]
###< blackfireio/blackfire-symfony-meta ###

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:

.platform.app.yaml
1
2
3
4
5
6
7
8
9
10
runtime:
    extensions:
        - apcu
        - blackfire
        - ctype
        - iconv
        - mbstring
        - pdo_pgsql
        - sodium
        - xsl

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:

.blackfire.yaml
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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
scenarios: |
    #!blackfire-player

    group login
        visit url('/login')
        submit button("Sign in")
            param username "admin"
            param password "admin"
            expect status_code() == 302

    scenario
        name "Submit a comment on the Amsterdam conference page"
        include login
        visit url('/fr/conference/amsterdam-2019')
            expect status_code() == 200
        submit button("Submit")
            param comment_form[author] 'Fabien'
            param comment_form[email] 'me@example.com'
            param comment_form[text] 'Such a good conference!'
            param comment_form[photo] file(fake('image', '/tmp', 400, 300, 'cats'), 'awesome-cat.jpg')
            expect status_code() == 302
        follow
            expect status_code() == 200
            expect not(body() matches "/Such a good conference/")
            # Wait for the workflow to validate the submissions
            wait 5000
        when env != "prod"
            visit url(webmail_url ~ '/messages')
                expect status_code() == 200
                set message_ids json("[*].id")
            with message_id in message_ids
                visit url(webmail_url ~ '/messages/' ~ message_id ~ '.html')
                    expect status_code() == 200
                    set accept_url css("table a").first().attr("href")
                include login
                visit url(accept_url)
                    # we don't check the status code as we can deal
                    # with "old" messages which do not exist anymore
                    # in the DB (would be a 404 then)
        when env == "prod"
            visit url('/admin')
                expect status_code() == 302
            follow
            click link("Comments")
                expect status_code() == 200
                set comment_ids css('table.table tbody tr').extract('data-id')
            with id in comment_ids
                visit url('/admin/comment/review/' ~ id)
                    # we don't check the status code as we scan all comments,
                    # including the ones already reviewed
        visit url('/fr/')
            wait 5000
        visit url('/fr/conference/amsterdam-2019')
            expect body() matches "/Such a good conference/"

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.

Andare oltre

  • Il libro di Blackfire: PHP Code Performance Explained;
  • Guida a Blackfire su SymfonyCasts.
Previous page Localizzazione di un'applicazione
Next page Scoprire il cuore di Symfony
This work, including the code samples, is licensed under a Creative Commons BY-NC-SA 4.0 license.
TOC
    Version

    Symfony 5.4 is backed by

    Online Symfony certification, take it now!

    Online Symfony certification, take it now!

    Be trained by SensioLabs experts (2 to 6 day sessions -- French or English).

    Be trained by SensioLabs experts (2 to 6 day sessions -- French or English).

    Version:
    Locale:
    ebook

    This book is backed by:

    see all backers

    Symfony footer

    Avatar of Raphaëll Roussel, a Symfony contributor

    Thanks Raphaëll Roussel for being a Symfony contributor

    1 commit • 4 lines changed

    View all contributors that help us make Symfony

    Become a Symfony contributor

    Be an active part of the community and contribute ideas, code and bug fixes. Both experts and newcomers are welcome.

    Learn how to contribute

    Symfony™ is a trademark of Symfony SAS. All rights reserved.

    • What is Symfony?

      • What is Symfony?
      • Symfony at a Glance
      • Symfony Components
      • Symfony Releases
      • Security Policy
      • Logo & Screenshots
      • Trademark & Licenses
      • symfony1 Legacy
    • Learn Symfony

      • Symfony Docs
      • Symfony Book
      • Reference
      • Bundles
      • Best Practices
      • Training
      • eLearning Platform
      • Certification
    • Screencasts

      • Learn Symfony
      • Learn PHP
      • Learn JavaScript
      • Learn Drupal
      • Learn RESTful APIs
    • Community

      • Symfony Community
      • SymfonyConnect
      • Events & Meetups
      • Projects using Symfony
      • Contributors
      • Symfony Jobs
      • Backers
      • Code of Conduct
      • Downloads Stats
      • Support
    • Blog

      • All Blog Posts
      • A Week of Symfony
      • Case Studies
      • Cloud
      • Community
      • Conferences
      • Diversity
      • Living on the edge
      • Releases
      • Security Advisories
      • Symfony Insight
      • Twig
      • SensioLabs Blog
    • Services

      • SensioLabs services
      • Train developers
      • Manage your project quality
      • Improve your project performance
      • Host Symfony projects

      Powered by

    Follow Symfony