Aller au contenu

Pyroscope

Pyroscope est le service de profiling continu de PerfShop. Il reçoit en push les profils CPU, allocations mémoire et contention de verrous produits par l'agent Java Pyroscope embarqué dans le backend, les stocke localement, et alimente les panels Flamegraph des dashboards APM.

Source de vérité

Cette page est tirée de pyroscope/pyroscope-config.yml, des JAVA_OPTS du backend dans les fichiers compose, et de la datasource Pyroscope dans grafana/provisioning/datasources/pyroscope.yml.

Pourquoi Pyroscope ?

Le profiling continu (« continuous profiling ») est le pilier moins connu des « quatre piliers de l'observabilité » (métriques, logs, traces, profils). Là où les métriques disent « combien », les traces disent « où dans le code », les profils disent « quelle ligne précise consomme ».

Concrètement, dans PerfShop, Pyroscope permet de répondre à des questions du type :

  • « Quand le chaos CPU est actif, quelle méthode Java consomme exactement le CPU ? »
  • « Quelle classe alloue le plus d'objets quand le chaos OutOfMemoryError est en cours ? »
  • « Sur quel synchronized les threads se bloquent-ils pendant la simulation Race Condition (A8) ? »

Les réponses sont visuelles : flamegraphs dans Grafana, où la largeur de chaque rectangle représente le temps CPU consommé par la méthode (ou la mémoire allouée, ou le temps bloqué sur un verrou).

Architecture

flowchart LR
  subgraph BE["perfshop-app (JVM)"]
    direction TB
    APP["Spring Boot 3.2"]
    PA["agent Pyroscope<br/>pyroscope.jar"]
    APP -.injecté.-> PA
  end

  PYRO["perfshop-pyroscope<br/>(grafana/pyroscope:latest)<br/>filesystem backend"]

  GRAF["Grafana<br/>(datasource Pyroscope)"]

  PA -->|"JFR HTTP push :4040<br/>(CPU, alloc, lock)"| PYRO
  PYRO -->|"datasource Pyroscope<br/>(query flamegraphs)"| GRAF

Pyroscope fonctionne en mode push uniquement : c'est l'agent qui pousse périodiquement les profils, pas Pyroscope qui scrape. C'est différent de Prometheus, et c'est cohérent avec le modèle JFR (un fichier par fenêtre temporelle).

Configuration Pyroscope

server:
  http_listen_port: 4040
  log_level: warn

storage:
  backend: filesystem
  filesystem:
    dir: /var/pyroscope/data

scrape_configs: []
Paramètre Valeur Effet
http_listen_port 4040 Port HTTP unique — sert à la fois pour le push (POST /ingest) et pour l'API query (Grafana)
log_level warn Niveau de log Pyroscope lui-même
storage.backend filesystem Stockage local sur le volume nommé pyroscope-data
storage.filesystem.dir /var/pyroscope/data Chemin interne, monté sur le volume nommé
scrape_configs: [] (vide) Aucune cible scrapée — mode push only

Le port hôte par défaut est 4040 (variable PYROSCOPE_HTTP_PORT).

Pas de retention configurée

PerfShop n'a pas de politique de rétention explicite côté Pyroscope — c'est volontaire pour le contexte pédagogique (les profils restent disponibles pour analyse différée pendant toute la durée d'un TP). En production réelle, on positionnerait compactor.retention_period pour borner la consommation disque.

Agent Pyroscope côté backend

L'agent Java Pyroscope est embarqué dans l'image perfshop-backend (chemin /agents/pyroscope.jar) et activé via JAVA_OPTS :

-javaagent:/agents/pyroscope.jar
-Dpyroscope.server.address=http://perfshop-pyroscope:4040
-Dpyroscope.application.name=perfshop
-Dpyroscope.format=jfr
-Dpyroscope.profiler.event=cpu
-Dpyroscope.profiler.alloc=512k
-Dpyroscope.profiler.lock=10ms
-Dpyroscope.profilingInterval=PT0.02S

Décodage des propriétés

Propriété Effet
pyroscope.server.address Endpoint Pyroscope en DNS Docker interne
pyroscope.application.name=perfshop Identifie l'application dans Pyroscope — apparaît comme service: perfshop dans Grafana
pyroscope.format=jfr Format Java Flight Recorder — l'agent utilise les API JFR de la JVM pour collecter sans overhead significatif
pyroscope.profiler.event=cpu Profil CPU activé — c'est le profil principal
pyroscope.profiler.alloc=512k Profil d'allocations heap — un échantillon est pris toutes les 512 Ko alloués (approximativement)
pyroscope.profiler.lock=10ms Profil de contention de verrous — toute attente sur un verrou ≥ 10 ms est échantillonnée
pyroscope.profilingInterval=PT0.02S Échantillonnage CPU toutes les 20 ms (notation ISO 8601 Duration)

Trois profils en parallèle

L'agent Pyroscope produit donc trois flux de profils simultanément, sans interférer entre eux :

flowchart TB
  AGENT["pyroscope.jar"]

  AGENT --> CPU["Profil CPU<br/>sample 20ms<br/>perf_event ou itimer"]
  AGENT --> ALLOC["Profil allocations<br/>1 sample / 512 Ko alloués"]
  AGENT --> LOCK["Profil lock contention<br/>blocages ≥ 10 ms"]

  CPU --> P1[("Pyroscope<br/>profil cpu")]
  ALLOC --> P2[("Pyroscope<br/>profil alloc")]
  LOCK --> P3[("Pyroscope<br/>profil lock")]

Profil CPU — perf_event vs itimer

Pyroscope choisit automatiquement la méthode d'échantillonnage selon l'environnement :

Environnement Méthode Particularités
Linux natif (VPS, serveur physique) perf_event Échantillonne le CPU hardware, plus précis, mais nécessite des capabilities Linux particulières
Docker Desktop (Windows / macOS / Linux virtualisé) itimer Échantillonne via les timers logiciels POSIX, fonctionne dans tous les environnements containerisés

C'est pour cette raison que les dashboards APM Élève et Formateur exposent deux panels Flamegraph CPU côté à côté :

  • CPU Flamegraph — Linux (perf_event) — vide sous Docker Desktop
  • CPU Flamegraph — Docker Desktop / Windows / macOS (itimer) — vide sur Linux natif

L'un des deux est toujours vide selon l'environnement, mais l'étudiant peut comprendre la différence et lire celui qui contient des données.

Profil d'allocations heap

Le profil alloc capture l'origine des allocations mémoire — quelles méthodes allouent le plus d'objets, à quelle fréquence. C'est ce que regarde le panel « Heap Flamegraph — allocations mémoire (F3-OOM) » du dashboard APM Formateur.

Quand le chaos backend memory est actif et que le heap se remplit, l'étudiant peut :

  1. Ouvrir le panel Heap Flamegraph,
  2. Identifier la méthode au sommet du graphe (la plus large),
  3. Corréler avec le code source pour comprendre quelle classe est responsable de la croissance.

Profil de contention de verrous

Le profil lock capture les threads qui attendent sur un synchronized ou un ReentrantLock. Le panel « Lock Contention Flamegraph — verrous JVM (A8 Race Condition) » met en évidence les hot-spots de contention.

C'est l'outil principal pour le scénario chaos pédagogique A8 — Race Condition : un thread tient un verrou trop longtemps, les autres s'accumulent en attente, le profil lock montre exactement où.

Datasource Grafana

- name: Pyroscope
  type: grafana-pyroscope-datasource
  uid: pyroscope
  access: proxy
  url: http://perfshop-pyroscope:4040
  isDefault: false
  editable: true

Configuration minimale — le plugin natif Grafana grafana-pyroscope-datasource gère tout : sélection du profil (cpu, alloc, lock), filtrage par labels, comparaison entre deux fenêtres temporelles.

Lecture d'un flamegraph — guide rapide

flowchart TB
  R["Racine (root)<br/>= 100 % du temps CPU<br/>de la fenêtre observée"]
  R --> M1["Tomcat thread loop<br/>~80 %"]
  R --> M2["GC threads<br/>~12 %"]
  R --> M3["Autres<br/>~8 %"]

  M1 --> M11["doFilter (LicenseInterceptor)<br/>~5 %"]
  M1 --> M12["doFilter (ChaosInterceptor)<br/>~30 %"]
  M1 --> M13["ProductController.list()<br/>~45 %"]

  M12 --> M121["CpuChaosScheduler.busyLoop()<br/>~28 %"]
Concept Lecture
Largeur d'un rectangle Proportion du temps CPU consommée par la méthode et toutes ses descendantes
Hauteur (axe vertical) Profondeur de la pile d'appels
Empilement Une méthode appelée par la méthode du dessus
Couleur Décorative (palette aléatoire pour distinguer visuellement)
Hot path Le chemin le plus large du root jusqu'à une feuille — c'est ce sur quoi se concentrer

L'erreur classique d'un débutant est de regarder la hauteur : ce n'est pas un indicateur. Seule la largeur compte.

Volumes

Volume Montage Contenu
pyroscope-data (volume nommé) /var/pyroscope/data Profils stockés en filesystem, organisés par série temporelle
./pyroscope/pyroscope-config.yml (bind mount) /etc/pyroscope/pyroscope-config.yml Configuration Pyroscope (lecture seule)

Ports

Service Port hôte Port container Variable d'env
perfshop-pyroscope 4040 4040 PYROSCOPE_HTTP_PORT

Pour aller plus loin

  • Vue d'ensemble — quatre signaux d'observabilité
  • Grafana — datasource Pyroscope
  • Dashboards livrés — panels Flamegraph des dashboards APM Élève et Formateur
  • Tempo — l'autre agent embarqué dans l'image backend
  • Section Chaos engineering (LOT 3) — scénarios qui exploitent le profiling continu (A8 Race Condition, F3 OutOfMemoryError, chaos CPU)