Gérer les performances
L'optimisation prématurée est la racine de tous les maux.
Peut-être avez-vous déjà lu cette citation auparavant, mais j’aimerais la citer en entier :
Nous devrions éviter les économies de bout de chandelles, disons dans environ 97 % des cas : l'optimisation prématurée est la racine de tous les maux. Pour autant, nous ne devrions pas ignorer ces occasions dans ces 3% cruciaux.
-- Donald Knuth
Même de petites améliorations de performance peuvent faire la différence, en particulier pour les sites e-commerce. Maintenant que l'application du livre d'or est prête pour les heures de pointe, voyons comment nous pouvons analyser ses performances.
La meilleure façon de trouver des optimisations de performance est d'utiliser un profileur. L'option la plus populaire de nos jours est Blackfire (Avertissement : je suis aussi le fondateur du projet Blackfire).
Découvrir Blackfire
Blackfire est composé de plusieurs parties :
- Un client qui déclenche des profils (l'outil Blackfire CLI ou une extension de navigateur web pour Google Chrome ou Firefox) ;
- Un agent qui prépare et agrège les données avant de les envoyer à blackfire.io pour affichage ;
- Une extension PHP (la sonde) qui analyse le code PHP.
Pour travailler avec Blackfire, vous devez d'abord vous inscrire.
Installez Blackfire sur votre machine locale en exécutant le script d'installation suivant :
1
$ curl https://installer.blackfire.io/installer.sh | bash
Cet installateur télécharge et installle l'outil Blackfire CLI.
Unr fois terminé, installez la sonde PHP sur toutes les versions de PHP disponibles :
1
$ sudo blackfire php:install
Et activez la sonde PHP pour notre projet :
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
Redémarrez le serveur web pour que PHP puisse charger Blackfire :
1 2
$ symfony server:stop
$ symfony server:start -d
L'outil Blackfire CLI doit être configuré avec vos identifiants client personnels (pour stocker vos profils de projet dans votre compte personnel). Vous les trouverez en haut de la page Settings/Credentials
. Exécutez la commande suivante en remplaçant les espaces réservés :
1
$ blackfire client:config --client-id=xxx --client-token=xxx
Configurer l'agent Blackfire sur Docker
Le service Blackfire agent a déjà été configuré dans la stack Docker Compose :
Pour communiquer avec le serveur, vous devez récupérer vos identifiants de serveur personnels (ces identifiants spécifient l'endroit où vous voulez stocker les profils - vous pouvez en créer un par projet) ; ils se trouvent au bas de la page Settings/Credentials
. Stockez-les comme secrets :
1 2 3 4
$ symfony console secrets:set BLACKFIRE_SERVER_ID
# xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
$ symfony console secrets:set BLACKFIRE_SERVER_TOKEN
# xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Vous pouvez maintenant lancer le nouveau conteneur :
1 2
$ docker compose stop
$ docker compose up -d
Réparer une installation Blackfire en panne
Si vous obtenez une erreur pendant le profilage, augmentez le niveau de log Blackfire pour obtenir plus d'informations :
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
Redémarrez le serveur web :
1 2
$ symfony server:stop
$ symfony server:start -d
Et suivez les logs :
1
$ symfony server:log
Profilez à nouveau et vérifiez les logs.
Configurer Blackfire en production
Blackfire est inclus par défaut dans tous les projets Platform.sh.
Définissez les informations de connexion du serveur comme secrets de 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
La sonde PHP est déjà activée comme n'importe quelle autre extention PHP nécessaire :
Configurer Varnish pour Blackfire
Avant de pouvoir déployer pour commencer le profilage, vous devez trouver un moyen de contourner le cache HTTP de Varnish, sinon Blackfire n'atteindra jamais l'application PHP. Vous n'allez autoriser que les demandes de profil provenant de votre machine locale à ignorer Varnish.
Récupérez votre adresse IP actuelle :
1
$ curl https://ifconfig.me/
Et utilisez-la pour configurer 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 {
Vous pouvez maintenant déployer.
Profiler les pages web
Vous pouvez profiler les pages web traditionnelles depuis Firefox ou Google Chrome grâce à leurs extensions dédiées.
Sur votre machine locale, n'oubliez pas de désactiver le cache HTTP dans config/packages/framework.yaml
lors du profilage : sinon, vous profilerez la couche de cache HTTP Symfony au lieu de votre propre code.
Pour avoir une meilleure idée de la performance de votre application en production, vous devez également profiler l'environnement "production". Par défaut, votre environnement local utilise l'environnement de "développement", ce qui ajoute un surcoût important (principalement pour collecter des données pour la web debug toolbar et le profileur Symfony).
Note
Comme nous allons profiler l'environnement de "production", il n'y a rien à changer dans la configuration puisque nous n'avions activé le cache Symfony HTTP que pour l'environnement de "développement" dans un précédent chapitre.
Le passage de votre machine locale à l'environnement de production peut se faire en changeant la variable d'environnement APP_ENV
dans le fichier .env.local
:
1
APP_ENV=prod
Ou vous pouvez utiliser la commande server:prod
:
1
$ symfony server:prod
N'oubliez pas de le remettre sur dev à la fin de votre session de profilage :
1
$ symfony server:prod --off
Profiler les ressources de l'API
Le profilage de l'API ou de la SPA est plus efficace en ligne de commande, en utilisant l'outil Blackfire CLI que vous avez installé précédemment :
1
$ blackfire curl `symfony var:export SYMFONY_PROJECT_DEFAULT_ROUTE_URL`api
La commande blackfire curl
accepte exactement les mêmes arguments et options que cURL.
Comparer les performances
Dans l'étape traitant du "Cache", nous avons ajouté une couche cache pour améliorer les performances de notre code, mais nous n'avons pas vérifié ni mesuré l'impact du changement sur les performances. Comme nous sommes tous très mauvais pour deviner ce qui sera rapide et ce qui est lent, vous pourriez vous retrouver dans une situation où l'optimisation rend votre application plus lente.
Vous devriez toujours mesurer l'impact de toute optimisation que vous faites avec un profileur. Blackfire facilite l'analyse grâce à sa fonction de comparaison.
Écrire les tests fonctionnels de boîte noire
Nous avons vu comment écrire des tests fonctionnels avec Symfony. Blackfire peut être utilisé pour écrire des scénarios de navigation qui peuvent être exécutés à la demande via le lecteur Blackfire. Rédigeons un scénario qui soumet un nouveau commentaire et le valide via le lien email en développement, et via l'interface d'admin en production.
Créez un fichier .blackfire.yaml
avec le contenu suivant :
Téléchargez le lecteur Blackfire pour pouvoir exécuter le scénario localement :
1 2
$ curl -OLsS https://get.blackfire.io/blackfire-player.phar
$ chmod +x blackfire-player.phar
Exécutez ce scénario en développement :
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
Ou en production :
1
$ ./blackfire-player.phar run --endpoint=`symfony cloud:env:url --pipe --primary` .blackfire.yaml --variable "webmail_url=NONE" --variable="env=prod" -vv
Les scénarios Blackfire peuvent également déclencher des profils pour chaque requête et exécuter des tests de performance en ajoutant l'option --blackfire
.
Automatiser les contrôles de performance
La gestion de la performance ne consiste pas seulement à améliorer la performance du code existant, mais aussi à vérifier qu'aucune régression de performance n'est introduite.
Le scénario décrit dans la section précédente peut être exécuté automatiquement dans un workflow d'intégration continue ou régulièrement en production.
Platform.sh permet également d'`exécuter les scénarios`_ à chaque fois que vous créez une nouvelle branche ou déployez en production pour vérifier automatiquement les performances du nouveau code.