Liveprof vous montrera quand et pourquoi les performances de votre application PHP ont changé



Bonjour, Habr! Je m'appelle Timur Shagiakhmetov, je suis développeur PHP chez Badoo .

La performance des applications est l'un des critères les plus importants pour la qualité du travail d'un programmeur. En matière d'optimisation des applications PHP, l'assistant est le profileur.

Récemment, nous avons parlé des outils que nous utilisons pour le profilage. Permettez-moi de vous rappeler: l'un des outils pour l'analyse des performances, lorsqu'il n'est pas clair quelles parties du code ont influencé l'augmentation du temps de génération de réponse, est XHProf . Il s'agit d'une extension pour PHP qui vous permet de profiler du code sur un serveur de combat et de l'améliorer par la suite.

Mais je voudrais également avoir un historique des changements de productivité, afin que vous puissiez suivre ce qui et quand a affecté sa détérioration, non? Pour ce faire, il y a environ un an, nous avons développé Liveprof , un outil de profilage automatique de toutes les requêtes avec une interface d'analyse des évolutions des performances des applications.

Notre outil vous permet d'analyser l'évolution des performances de n'importe quelle partie du code, de trouver les endroits où il a le plus chuté. Dans le même temps, il n'a pas besoin d'être spécifiquement activé et d'attendre que les statistiques s'accumulent - il est toujours actif et recueille des données pour une certaine fraction de toutes les demandes.

Dans cet article, je parlerai des détails d'implémentation et des fonctionnalités de l'utilisation de cet outil.

Un peu sur XHProf


Tout d'abord, quelques mots sur les fonctionnalités de XHProf lui-même. Il s'agit d'un profileur pour PHP écrit en C comme une extension. Il a été développé sur Facebook et publié dans le domaine public. Il dispose de plusieurs fourches ( uprofiler , Tideways ), entièrement compatibles au niveau du format de données de sortie.

XHProf définit des temporisateurs autour de tous les appels de fonction / méthode. Son utilisation implique des frais généraux. Mais ils ne sont pas si gros et permettent de l'utiliser en production.

Le résultat de XHProf est un tableau d'éléments au format suivant:

$data = [ 'parentMethodName==>childMethodName' => [ 'ct' => 1 'wt' => 8 'cpu' => 11 'mu' => 528 'pmu' => 0 ] ]; 



parentMethodName et childMethodName sont respectivement les méthodes parent et enfant;
ct - le nombre d'appels dans le contexte de la demande;
wt - temps d'exécution de la demande (comprend le temps passé par le processeur et le temps d'attente pour les E / S ou la réponse d'un autre service);
cpu - temps consacré par le processeur au traitement de la demande;
mu - modification de la consommation de mémoire après un appel de méthode;
pmu - modification de la consommation de mémoire maximale après un appel de méthode.

D'autres options sont également possibles.

XHProf contient également des outils pour visualiser les résultats ainsi obtenus. Pour chaque opération de profilage, nous obtenons un tableau avec un ensemble de paramètres pour chaque méthode.

Par exemple

résultat du tri à bulles
 <?php class ArrayGenerator { public function getRandomArray(int $count): array { $array = []; for ($i = 0; $i < $count; $i++) { $array[] = rand(0, 1000); } return $array; } } class BubbleSorter { public function sort(&$array): void { $len = count($array); for ($i = 0; $i < $len ; $i++) { for ($j = 0; $j < $len - $i - 1; $j++) { if ($array[$j] > $array[$j + 1]) { $this->swap($array[$j], $array[$j + 1]); } } } } private function swap(&$a, &$b): void { $tmp = $a; $a = $b; $b = $tmp; } public function isSorted(array $array): bool { $len = count($array); for ($i = 0; $i < $len - 1; $i++) { if ($array[$i] > $array[$i + 1]) { return false; } } return true; } } class ArrayPrinter { public function print(array $array, string $delimiter = ' '): void { echo implode($delimiter, $array) . PHP_EOL; } } xhprof_enable(); $n = 10; $arrayGenerator = new \ArrayGenerator(); $array = $arrayGenerator->getRandomArray($n); $sorter = new BubbleSorter(); if (!$sorter->isSorted($array)) { $sorter->sort($array); } $printer = new \ArrayPrinter(); $printer->print($array); $xhprof_data = xhprof_disable(); 




Vous pouvez parcourir chaque méthode pour savoir quelles méthodes ont utilisé le nombre de ressources.

Vous pouvez également consulter le graphique des appels en mettant en évidence les méthodes les plus gourmandes en ressources:



XHProf est utile pour analyser manuellement les performances de chaque demande. Mais il est également important pour nous de voir la situation dans son ensemble. Vous devez comprendre comment les performances ont changé au fil du temps. Pour ce faire, un outil a été développé qui permet de profiler les requêtes en mode automatique et de les analyser dans l'interface web.

Liveprof: agréger les résultats et conserver l'historique


Comment obtenir l'historique du profilage?

Vous devez d'abord configurer le lancement automatique du profileur et enregistrer les résultats. Les performances ne sont pas constantes et fluctuent d'un lancement à l'autre. Pour éviter l'influence de telles fluctuations, nous utilisons les données moyennes de plusieurs requêtes. Par conséquent, nous obtenons des résultats agrégés pour chaque requête, par exemple, minimum, maximum, moyenne et 95e centile. Cela aide à trouver des choses difficiles qui peuvent ne pas être appelées pour chaque demande.

Notre outil présente à la fois des avantages et des limites.

Ce que l'agrégateur peut faire:


  1. Profilage automatique de chaque Nième requête.
  2. Agrégation quotidienne des profils collectés.
  3. La possibilité de voir des graphiques des changements dans chaque paramètre mesurés par le profileur. Par exemple, wt, cpu, mu, pmu décrits ci-dessus.
  4. Voir le changement de performances de toute méthode pour un certain intervalle.
  5. Graphique de flamme basé sur les dernières données agrégées.
  6. Rechercher des requêtes qui appellent une méthode spécifique

Limitations:


  1. Étant donné que notre outil est un outil d'agrégation, vous ne pouvez pas découvrir les performances d'une requête (par exemple, la plus lente) - nous obtenons les résultats en moyenne sur le dernier jour. Mais cela suffit pour évaluer la dynamique globale des performances. Si une demande a glissé dans la vitesse d'exécution, la valeur moyenne, le 95e centile et le temps d'exécution maximal changeront.
  2. Vous ne pouvez pas restaurer sans ambiguïté la pile d'appels complète, car XHProf ne renvoie que des paires parent-enfant uniques avec la somme des valeurs des ressources dépensées.
  3. Erreur d'exécution de la requête liée à la surcharge XHProf. La différence n'est pas si grande, mais elle doit être prise en compte lors de la mesure du temps d'exécution de la requête.

Comment utiliser le profileur


  1. Tout d'abord, le profileur doit être connecté au site ou au script. La façon la plus pratique d'utiliser l' outil est de lancer automatiquement le profileur :

     php composer.phar require badoo/liveprof # Run a script to configure database LIVE_PROFILER_CONNECTION_URL=mysql://db_user:db_password@db_mysql:3306/Profiler?charset=utf8 php vendor/badoo/liveprof/bin/install.php 

    Il prend en charge les versions de PHP à partir de la version 5.4 et son utilisation est lourde de charges minimales, ce qui vous permet de l'utiliser dans un environnement de combat. L'outil détecte automatiquement l'extension de profileur utilisée: XHProf , uprofiler ou Tideways . Au démarrage, vous devez spécifier les paramètres de connexion à la base de données et les paramètres de profilage.

    Exemple d'utilisation dans le code avec les paramètres par défaut:

     <?php include 'vendor/autoload.php'; \Badoo\LiveProfiler\LiveProfiler::getInstance()->start(); // Code is here 

    Les résultats de profilage sont enregistrés dans la base de données. Une fois par jour, un processus d'agrégation a lieu. Pour ce faire, sélectionnez tous les enregistrements d'une demande spécifique par jour et calculez les fonctions agrégées pour chacun des paramètres. Les fonctions d'agrégation peuvent être développées ou redéfinies.

    Les éléments suivants sont désormais disponibles:

    • au moins par jour;
    • maximum par jour;
    • moyenne quotidienne
    • 95e centile de la journée.

  2. Le client Web agrégateur est utilisé pour configurer l'agrégation et afficher les résultats. La façon la plus simple de l'installer dans un conteneur Docker:

     git clone https://github.com/badoo/liveprof-ui.git cd liveprof-ui docker-compose up web 
  3. Avant le premier démarrage, vous devez configurer les paramètres de connexion à la base de données, une liste de champs et les fonctions d'agrégation utilisées dans le fichier de configuration src / config / services.yaml. Exécutez ensuite le script d'installation:

     docker-compose exec web bash install.sh 
  4. Il est nécessaire d'enregistrer automatiquement des scripts d'agrégation et de nettoyage des anciennes données dans les couronnes:

     # script aggregates all profiles for previous day, add it if you don't use a queue for aggregation jobs (parameter aggregator.use_jobs_in_aggregation=false) 0 2 * * * docker-compose -f %PATH_TO_PROJECT%/docker-compose.yml run --rm --entrypoint '/usr/local/bin/php /app/bin/cli.php cron:aggregate-all-profiles' web # script removes old aggregated data, by default > 200 days 0 1 * * * docker-compose -f %PATH_TO_PROJECT%/docker-compose.yml run --rm --entrypoint '/usr/local/bin/php /app/bin/cli.php cron:remove-old-profiles' web 200 

  5. Pour remplir avec des données de test, vous pouvez exécuter le script:

     docker-compose exec web php /app/bin/cli.php example:a-week-degradation 

Description de l'interface


L'interface Web est disponible à: 127.0.0.1:8000.

Par défaut, une page avec une liste de requêtes agrégées s'ouvre. Il permet de trouver facilement une requête qui vous intéresse, de trier toutes les requêtes en fonction de l'un des paramètres et de ré-agréger une requête spécifique pour voir les derniers résultats:



Une page avec une liste de méthodes et de graphiques des changements de performances est la plus utilisée lorsque vous travaillez avec l'outil. Il vous permet de parcourir la pile des appels, de surveiller la consommation de chaque paramètre, ainsi que des graphiques des changements de performances pour un certain intervalle:



Une page avec une liste complète des méthodes appelées vous permet de trouver rapidement la méthode qui vous intéresse et de voir les graphiques en allant sur la page des graphiques:


La page avec le graphique de flamme de la dernière requête agrégée vous permet d'identifier visuellement les parties les plus lourdes.

L'utilisation de XHProf impose certaines limites à la précision du résultat. Cela est dû au fait que le profileur ne renvoie pas une arborescence d'appels complète, mais uniquement les paires parent-enfant. De plus, si une paire de méthodes a été appelée à différents endroits de l'application, nous obtenons ainsi le temps passé. Pour un graphique de flamme, vous devez avoir un arbre d'appel complet. Lors de la restauration d'un tel arbre, les valeurs des paramètres sont normalisées en tenant compte du temps passé par les parents.


Une page avec une liste de méthodes qui sont devenues plus lentes pendant l'intervalle sélectionné.

De plus, pour chaque méthode, vous pouvez voir lequel des appels enfants a le plus affecté les performances. Par exemple, dans la capture d'écran ci-dessous, vous pouvez voir que la méthode ServiceApi::getAvailableServices() commencé à s'exécuter 116 ms plus lentement. La raison en était l'ajout d'un appel à ServiceApi::getGifts() (modification de 56 ms) et une augmentation du nombre d'appels à la méthode ServiceApi::getConfigForList() de 1 à 5 (encore 50 ms):



Si l'on ne sait pas à l'avance quelle requête les performances ont le plus changé, une page avec une liste de méthodes devenues plus lentes sans référence à une requête spécifique aidera:


Une page qui recherche des requêtes qui appellent une méthode particulière.

Il vous permet de comparer le temps d'exécution dans différentes requêtes. Également utile pour trouver du code inutilisé:



Caractéristiques de personnalisation


L'outil offre de nombreuses possibilités de personnalisation:

  • vous pouvez ajouter vos propres fonctions d'agrégation qui calculent une certaine valeur en fonction du tableau passé de valeurs de paramètres;
  • Vous pouvez modifier la base de données pour stocker les profils et les résultats agrégés (SQLite, MySQL et PostgreSQL sont désormais pris en charge, mais vous pouvez en utiliser d'autres dans la liste disponible pour Doctrine DBAL );
  • Vous pouvez remplacer le gestionnaire de connexions à la base de données et implémenter vos méthodes d'obtention de données;
  • Vous pouvez utiliser l'interface Web à la fois en tant que projet autonome et dans n'importe quel cadre (par exemple, un panneau de configuration de site). Un exemple:

     public function profileListAction() {      <i>//Some custom logic before</i>   $this->checkPermissions();   $App = new \Badoo\LiveProfilerUI\LiveProfilerUI();   $Page = $App->getPage('profile_method_list_page');   return $Page->setData($data)->render(); } 

Conclusion


J'espère que notre outil sera utile à d'autres développeurs. Il permettra de vérifier le changement de performance de n'importe quelle partie du code sans utiliser de temporisateurs supplémentaires. Cela facilitera également le processus d'optimisation, car vous pouvez maintenant voir ce qui a affecté la dégradation des performances de l'application au fil du temps.

Il est disponible sur GitHub: github.com/badoo/liveprof , l'interface web est github.com/badoo/liveprof-ui .

L'outil est en cours de développement actif et peut contenir des erreurs. Espérons qu'avec la participation de la communauté, cela ira encore mieux. Les plans incluent l'ajout de la prise en charge d'autres profileurs en plus de XHProf, ainsi que l'extension de la liste des bases de données prises en charge.

Envoyez-nous vos commentaires et vos questions sur l'utilisation dans Telegram , les bugs et les pull pulls - directement à GitHub . Nous apprécions les commentaires et suggestions!

Un merci spécial à Gregory pour l'idée et la première implémentation.

Source: https://habr.com/ru/post/fr436364/


All Articles