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
synchronizedles 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 DesktopCPU 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 :
- Ouvrir le panel Heap Flamegraph,
- Identifier la méthode au sommet du graphe (la plus large),
- 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)