Profiler des applications Python

Cette page explique comment modifier votre application Python pour capturer les données de profilage et les envoyer à votre projet Google Cloud. Pour obtenir des informations générales sur le profilage, consultez la page Concepts du profilage.

Types de profils pour Python :

  • Temps CPU
  • Durée d'exécution (thread principal)

Versions de langages compatibles avec Python :

  • Python 3.6 ou version supérieure.

Versions d'agent de profilage compatibles :

  • La version la plus récente de l'agent est compatible. En général, les versions datant de plus d'un an ne sont pas compatibles. Nous vous recommandons d'utiliser la version la plus récente de l'agent.

Systèmes d'exploitation compatibles :

  • Linux. Le profilage d'applications Python est compatible avec les noyaux Linux dont la bibliothèque C standard est mise en œuvre avec glibc ou musl. Pour obtenir des informations de configuration spécifiques aux noyaux Linux Alpine, reportez-vous à la page Exécution sous Linux Alpine.

Environnements compatibles :

Activer l'API Profiler

Avant d'utiliser l'agent de profilage, assurez-vous que l'API Profiler sous-jacente est activée. Vous pouvez vérifier l'état de l'API et l'activer, si nécessaire, à l'aide de Google Cloud CLI ou de Google Cloud Console :

CLI gcloud

  1. Si vous n'avez pas encore installé Google Cloud CLI sur votre poste de travail, consultez la documentation de Cloud CLI.

  2. Exécutez la commande suivante :

    gcloud services enable cloudprofiler.googleapis.com
    

Pour en savoir plus, consultez les sections sur gcloud services

Console Google Cloud

  1. Enable the required API.

    Enable the API

  2. Si API activée s'affiche, cela signifie que l'API est déjà activée. Sinon, cliquez sur le bouton Activer.

Attribuer un rôle IAM à un compte de service

Si vous déployez votre application sur des ressources Google Cloud, si vous utilisez le compte de service par défaut et que vous n'avez pas modifié les autorisations de rôle accordées à ce compte de service, vous pouvez ignorer cette section.

Si vous effectuez l'une des opérations suivantes, vous devez attribuer au compte de service le rôle IAM Agent Cloud Profiler (roles/cloudprofiler.agent):

  1. Vous utilisez le compte de service par défaut, mais vous avez modifié ses autorisations de rôle.
  2. Vous utilisez un compte de service créé par l'utilisateur.
  3. Vous utilisez Workload Identity. Accordez le rôle Agent Cloud Profiler au compte de service Kubernetes.

Vous pouvez attribuer un rôle IAM à un compte de service à l'aide de la console Google Cloud ou de Google Cloud CLI. Par exemple, vous pouvez utiliser la commande gcloud projects add-iam-policy-binding:

gcloud projects add-iam-policy-binding GCP_PROJECT_ID \
    --member serviceAccount:MY_SVC_ACCT_ID@GCP_PROJECT_ID.iam.gserviceaccount.com \
    --role roles/cloudprofiler.agent

Avant d'utiliser la commande précédente, remplacez les éléments suivants:

  • GCP_PROJECT_ID : ID de votre projet
  • MY_SVC_ACCT_ID : nom de votre compte de service.

Pour en savoir plus, consultez la page Gérer l'accès aux projets, aux dossiers et aux organisations.

Utiliser Cloud Profiler

Pour connaître les bonnes pratiques relatives à l'utilisation de Python, reportez-vous à la section Configurer un environnement de développement Python.

Compute Engine

Avec Compute Engine, procédez comme suit :

  1. Installez le compilateur C/C++ et les outils de développement :

    sudo apt-get install -y build-essential
    
  2. Installez pip :

    sudo apt-get install -y python3-pip
    
  3. Installez le package Profiler :

    pip3 install google-cloud-profiler
    
  4. Importez le module googlecloudprofiler et appelez la fonction googlecloudprofiler.start le plus tôt possible dans votre code d'initialisation :

    import googlecloudprofiler
    
    
    def main():
        # Profiler initialization. It starts a daemon thread which continuously
        # collects and uploads profiles. Best done as early as possible.
        try:
            googlecloudprofiler.start(
                service="hello-profiler",
                service_version="1.0.1",
                # verbose is the logging level. 0-error, 1-warning, 2-info,
                # 3-debug. It defaults to 0 (error) if not set.
                verbose=3,
                # project_id must be set if not running on GCP.
                # project_id='my-project-id',
            )
        except (ValueError, NotImplementedError) as exc:
            print(exc)  # Handle errors here

    Vous devez spécifier le paramètre service dans la fonction start. Pour filtrer les données en fonction de la version de l'application dans l'interface de Profiler, spécifiez le paramètre service_version. Pour en savoir plus sur le dépannage et les exceptions, consultez la section Dépannage.

GKE

Avec GKE, procédez comme suit :

  1. Modifiez votre Dockerfile pour installer le package Profiler :

    FROM python:3
    ...
    RUN apt-get update && apt-get install -y build-essential python3-pip
    RUN pip3 install google-cloud-profiler
    
  2. Importez le module googlecloudprofiler et appelez la fonction googlecloudprofiler.start le plus tôt possible dans votre code d'initialisation :

    import googlecloudprofiler
    
    
    def main():
        # Profiler initialization. It starts a daemon thread which continuously
        # collects and uploads profiles. Best done as early as possible.
        try:
            googlecloudprofiler.start(
                service="hello-profiler",
                service_version="1.0.1",
                # verbose is the logging level. 0-error, 1-warning, 2-info,
                # 3-debug. It defaults to 0 (error) if not set.
                verbose=3,
                # project_id must be set if not running on GCP.
                # project_id='my-project-id',
            )
        except (ValueError, NotImplementedError) as exc:
            print(exc)  # Handle errors here

    Vous devez spécifier le paramètre service dans la fonction start. Pour filtrer les données en fonction de la version de l'application dans l'interface de Profiler, spécifiez le paramètre service_version. Pour en savoir plus sur le dépannage et les exceptions, consultez la section Dépannage.

Environnement flexible

Pour l'environnement flexible App Engine, procédez comme suit :

  1. Ajoutez google-cloud-profiler à votre fichier requirements.txt.

  2. Importez le module googlecloudprofiler et appelez la fonction googlecloudprofiler.start le plus tôt possible dans votre code d'initialisation.

Dans App Engine, les paramètres service et service_version sont dérivés de votre environnement d'exploitation. Pour en savoir plus sur le dépannage et les exceptions, consultez la section Dépannage.

Environnement standard

Pour l'environnement standard App Engine, qui requiert l'utilisation de l'environnement d'exécution Python 3, procédez comme suit :

  1. Ajoutez google-cloud-profiler à votre fichier requirements.txt.

  2. Importez le module googlecloudprofiler et appelez la fonction googlecloudprofiler.start le plus tôt possible dans votre code d'initialisation.

Dans App Engine, les paramètres service et service_version sont dérivés de votre environnement d'exploitation. Pour en savoir plus sur le dépannage et les exceptions, consultez la section Dépannage.

Fonction start

La fonction googlecloudprofiler.start crée un thread daemon qui collecte et importe des profils en continu. Vous devez appeler start une seule fois et le plus tôt possible dans votre application.

Paramètre Description
service1 (Obligatoire) Nom du service en cours de profilage. Pour connaître les restrictions relatives au nom de service, consultez la section Arguments de nom et de version de service.
service_version1 (Facultatif) Version du service en cours de profilage. Pour connaître les restrictions relatives à la version de service, consultez la section Arguments de nom et de version de service.
verbose (Facultatif) Niveau de journalisation. Pour en savoir plus sur les niveaux de journalisation, consultez la section Journaliser avec l'agent.

La valeur par défaut est 0 (Erreur).
project_id2 (Facultatif) ID de votre projet Google Cloud.
disable_cpu_profiling (Facultatif) Pour désactiver le profilage du temps CPU, définissez disable_cpu_profiling=True.

Ce paramètre ne s'utilise qu'avec Python 3.2 ou une version ultérieure. Il est ignoré dans toutes les autres versions de Python, car elles ne permettent pas le profilage du processeur.

La valeur par défaut est False (Faux).
disable_wall_profiling (Facultatif) Pour désactiver le profilage de la durée d'exécution, définissez disable_wall_profiling=True.

Ce paramètre est compatible avec Python 3.6 ou version ultérieure. Il est ignoré dans toutes les autres versions de Python, car elles ne permettent pas le profilage de la durée d'exécution.

Pour connaître les restrictions de la fonction start lorsque le profilage de la durée d'exécution est activé, consultez la section Limites.

La valeur par défaut est False (Faux).

1 Uniquement disponible pour Compute Engine et GKE. Pour App Engine, la valeur est dérivée de l'environnement.
2 Pour Google Cloud, la valeur est dérivée de l'environnement. Pour les environnements autres que Google Cloud, vous devez fournir une valeur. Pour en savoir plus, consultez la page Profiler des applications s'exécutant en dehors de Google Cloud.

Analyser des données

Une fois que Profiler a collecté des données, vous pouvez les afficher et les analyser dans son interface.

Dans la console Google Cloud, accédez à la page Profiler:

Accéder à Profiler

Vous pouvez également accéder à cette page à l'aide de la barre de recherche.

Arguments de nom et de version de service

Lorsque vous chargez l'agent Profiler, vous devez spécifier un argument de nom de service et un argument facultatif de version de service pour le configurer.

Le nom de service permet à Profiler de collecter des données de profilage pour toutes les instances dupliquées de ce service. Le service du profileur assure un taux de collecte de l'ordre d'un profil par minute, en moyenne, et ce pour chaque nom de service dans chaque combinaison de zones et de versions de service.

Par exemple, si deux versions d'un service s'exécutent sur des instances dupliquées dans trois zones, le profileur créera en moyenne six profils par minute pour ce service.

Si vous utilisez différents noms de service pour vos instances dupliquées, votre service sera profilé plus souvent que nécessaire, entraînant une surcharge proportionnelle.

Lorsque vous sélectionnez un nom de service, respectez ces instructions :

  • Choisissez un nom qui représente clairement le service dans votre architecture d'application. Le choix du nom de service est moins important si vous n'exécutez qu'un seul service ou qu'une seule application. En revanche, il est plus important lorsque votre application s'exécute sous la forme d'un ensemble de microservices, par exemple.

  • Assurez-vous de ne pas utiliser de valeurs spécifiques au processus, telles qu'un ID de processus, dans la chaîne du nom de service.

  • La chaîne du nom de service doit correspondre à l'expression régulière ci-dessous :

    ^[a-z0-9]([-a-z0-9_.]{0,253}[a-z0-9])?$

Nous vous recommandons d'utiliser une chaîne statique, telle que imageproc-service, comme nom de service.

La version de service est facultative. Si vous la spécifiez, Profiler peut regrouper les informations de profilage de plusieurs instances et les afficher correctement. Vous pouvez spécifier ce paramètre pour marquer différentes versions de vos services au fur et à mesure de leur déploiement. L'interface utilisateur de Profiler vous permet de filtrer les données par version de service. De cette façon, vous pouvez comparer les performances des versions de code les plus anciennes et les plus récentes.

La valeur de l'argument service-version est une chaîne de forme libre, mais les valeurs de cet argument ressemblent généralement à des numéros de version, par exemple 1.0.0 ou 2.1.2.

Journaliser avec l'agent

Par défaut, l'agent de profilage journalise les messages dont le niveau de gravité est error. Pour configurer l'agent de sorte qu'il journalise les messages dont le niveau de gravité est inférieur, spécifiez le paramètre verbose lors du démarrage de l'agent. Le paramètre verbose accepte quatre valeurs :

  • 0 : erreur
  • 1 : avertissement
  • 2 : information
  • 3 : débogage

Si vous définissez le paramètre verbose sur 1 dans l'appel de start, les messages dont le niveau de gravité est Warning ou Error sont journalisés, alors que les messages Informational et Debug sont ignorés.

Pour journaliser tous les messages, définissez verbose sur 3 lors du démarrage de l'agent :

googlecloudprofiler.start(service='service_name', verbose=3)

Dépannage

Dans cette section, vous trouverez la liste des restrictions, des exceptions et des problèmes connus spécifiques au profilage des applications Python. Consultez la page Dépannage pour obtenir de l'aide concernant les problèmes courants.

Limites

Type de profil Restrictions et limitations
Durée d'exécution
  • Uniquement disponible pour le profilage des threads principaux.
  • La fonction start du profil doit être appelée à partir du thread principal.
  • Le gestionnaire de signal de Profiler ne s'exécute que sur le thread principal. Si le thread principal ne peut pas s'exécuter, aucune donnée de profilage n'est collectée.

Exceptions

Erreur Cause Solution
Erreur NotImplementedError générée lors de l'appel de start Application exécutée dans un environnement autre que Linux.
  • Exécutez l'application dans un environnement Linux.
Erreur ValueError générée lors de l'appel de start Les arguments de la fonction start ne sont pas valides. Il est impossible de déterminer les informations nécessaires à partir des variables d'environnement et des arguments, ou des profils si le profilage du temps CPU et de la durée d'exécution est désactivé.
  • Assurez-vous que le nom et la version du service répondent aux exigences définies à la section Arguments de nom et de version du service.
  • Si le profilage de la durée d'exécution est activé, assurez-vous d'appeler la fonction start à partir du thread principal.
  • Vérifiez que vous utilisez une version de Python compatible et que le profilage du temps CPU ou de la durée d'exécution est activé. Pour en savoir plus, consultez la section Fonction start.
  • Pour les exécutions en dehors de Google Cloud, vérifiez que vous avez défini le paramètre project_id sur start. Pour en savoir plus, consultez la section Fonction start.

Problèmes connus

Comportement Cause Solution
Vous n'obtenez aucune donnée de profil, ou vous avez activé un nouveau type de profil dans lequel des données de profil manquent. La cause de ce problème provient souvent de la configuration. Consultez la section Dépannage.
Dans uWSGI, les données de profil sur le temps CPU et celles sur la durée d'exécution manquent pour certains processus.

Lorsque uWSGI utilise plusieurs nœuds de calcul pour gérer les requêtes, le comportement par défaut consiste à n'effectuer l'initialisation de l'application que dans le processus principal ("maître"). Les processus dupliqués n'effectuent pas la séquence d'initialisation.

Si vous configurez l'agent de profilage dans la séquence d'initialisation de votre application, par exemple dans AppConfig.ready() dans une application Django, il en résulte que l'agent de profilage n'est pas configuré pour les processus dupliqués.

Pour effectuer l'initialisation de l'application dans tous les processus des nœuds de calcul, définissez l'option lazy-apps sur true.

La rubrique suivante de ce tableau présente un problème connexe susceptible de vous intéresser.

Dans uWSGI, vous obtenez les données de profil sur le temps CPU, mais pas celles sur la durée d'exécution.

Le profileur collectant les durées d'exécution dépend du module de signal Python. Lorsque l'interpréteur Python est compilé pour être compatible avec les threads, la configuration par défaut désactive la gestion des signaux personnalisés pour les processus dupliqués.

Pour les applications uWSGI, activez la gestion des signaux personnalisés en définissant l'option py-call-osafterwork sur true.

La rubrique précédente de ce tableau présente un problème connexe susceptible de vous intéresser.

Après avoir activé le profileur, le journal d'erreurs contient de nouvelles entrées :

BlockingIOError: [Errno 11] Resource temporarily unavailable Exception ignored when trying to write to the signal wakeup fd

Problème GitHub

Votre application est enregistrée avec le descripteur de fichier d'activation du signal, signal.set_wakeup_fd. Par défaut, si la mémoire tampon du descripteur de fichier se remplit, un avertissement est consigné dans stderr.

Lorsque Cloud Profiler collecte des profils, il déclenche des signaux à une fréquence élevée. Ce comportement peut entraîner le remplissage du tampon du descripteur de fichier.

Si votre application peut s'exécuter en toute sécurité lorsque des signaux sont perdus, vous pouvez utiliser Cloud Profiler. Si vous utilisez Python 3.7 ou une version ultérieure, et que vous souhaitez désactiver les messages d'avertissement, transmettez warn_on_full_buffer=False en tant que paramètre à signal.set_wakeup_fd.

Si votre application ne peut pas s'exécuter en toute sécurité lorsque des signaux sont perdus, nous vous recommandons de cesser d'utiliser Cloud Profiler. La poursuite de l'utilisation peut entraîner la perte de numéros de signaux et un nombre excessif d'entrées dans le journal d'erreurs.

Exécuter avec Linux Alpine

L'agent de profilage Python pour Linux Alpine n'est compatible qu'avec les configurations Google Kubernetes Engine.

Pour créer l'agent de profilage Python, vous devez installer le package build-base. Pour utiliser l'agent de profilage Python sur Alpine sans installer de dépendances supplémentaires sur l'image Alpine finale, vous pouvez créer une image en deux étapes, en compilant l'agent de profilage Python lors de la première étape. Par exemple, l'image Docker suivante est créée en plusieurs étapes afin de compiler et d'installer l'agent de profilage Python :

FROM python:3.7-alpine as builder

# Install build-base to allow for compilation of the profiling agent.
RUN apk add --update --no-cache build-base

# Compile the profiling agent, generating wheels for it.
RUN pip3 wheel --wheel-dir=/tmp/wheels google-cloud-profiler

FROM python:3.7-alpine

# Copy over the directory containing wheels for the profiling agent.
COPY --from=builder /tmp/wheels /tmp/wheels

# Install the profiling agent.
RUN pip3 install --no-index --find-links=/tmp/wheels google-cloud-profiler

# Install any other required modules or dependencies, and copy an app which
# enables the profiler as described in "Enable the profiler in your
# application".
COPY ./bench.py .

# Run the application when the docker image is run, using either CMD (as is done
# here) or ENTRYPOINT.
CMD python3 -u bench.py

Erreur d'authentification

Si vous utilisez des images Docker exécutées avec Linux Alpine (par exemple, golang:alpine ou simplement alpine), l'erreur d'authentification suivante peut s'afficher:

connection error: desc = "transport: authentication handshake failed: x509: failed to load system roots and no roots provided"

Sachez que pour que cette erreur apparaisse, vous devez avoir activé la journalisation avec l'agent.

L'erreur indique que lorsque les images Docker sont exécutées avec Linux Alpine, les certificats SSL racine ne sont pas installés par défaut. Ces certificats sont nécessaires pour que l'agent de profilage puisse communiquer avec l'API du profileur. Pour résoudre cette erreur, ajoutez la commande apk suivante à votre fichier Dockerfile :

FROM alpine
...
RUN apk add --no-cache ca-certificates

Vous devez ensuite recompiler et redéployer votre application.

Étape suivante