APM — Traces & Profiling¶
L'APM (Application Performance Monitoring) de PerfShop repose sur deux outils complémentaires : Grafana Tempo pour les traces distribuées et Pyroscope pour le profiling CPU continu.
Accessible via le dashboard Grafana PerfShop — APM Formateur (perfshop-apm-formateur).
Architecture¶
perfshop-app (Spring Boot)
├── OTel Java Agent 1.33.6 ──OTLP gRPC──► perfshop-tempo:4317
└── Pyroscope Agent 0.14.0 ──HTTP──────► perfshop-pyroscope:4040
│
Grafana (datasources)
├── Tempo uid=tempo
└── Pyroscope uid=pyroscope
Les deux agents sont injectés via JAVA_OPTS dans docker-compose.yml — aucune dépendance Maven.
Ils sont téléchargés au moment du build dans Dockerfile.synology.
Grafana Tempo¶
Informations¶
| Paramètre | Valeur |
|---|---|
| Image | grafana/tempo:2.4.2 |
| Port HTTP (API) | 3200 |
| Port OTLP gRPC | 4317 |
| Port OTLP HTTP | 4318 |
| Datasource UID | tempo |
| Stockage | Volume Docker tempo-data (local) |
Configuration clé (tempo/tempo-config.yml)¶
distributor:
receivers:
otlp:
protocols:
grpc:
endpoint: 0.0.0.0:4317
http:
endpoint: 0.0.0.0:4318
metrics_generator:
storage:
remote_write:
- url: http://prometheus:9090/api/v1/write
Le metrics_generator pousse les RED metrics (Rate, Errors, Duration) vers Prometheus,
permettant de croiser traces et métriques dans un même dashboard.
Vérification¶
# Vérifier que Tempo reçoit des traces
curl "http://localhost:3200/api/search?q=%7B%7D&limit=5"
# Attendu : {"traces": [...]}
Version fixée à 2.4.2
Les versions 2.5+ introduisent une architecture distribuée (live-store + ring)
incompatible avec le mode single-binary sans Kafka ni memberlist cluster.
Ne pas upgrader sans tester le démarrage (docker logs perfshop-tempo).
WAL à purger entre versions
Si on change de version Tempo, le format WAL change (vParquet). Il faut impérativement supprimer le volume avant de redémarrer :
Pyroscope¶
Informations¶
| Paramètre | Valeur |
|---|---|
| Image | grafana/pyroscope:1.18.1 |
| Port HTTP | 4040 |
| Datasource UID | pyroscope |
| Type datasource Grafana | grafana-pyroscope-datasource |
Modes de profiling CPU¶
Le mode Pyroscope dépend du fichier compose utilisé :
| Fichier compose | Événement | Mécanisme | Stacks kernel |
|---|---|---|---|
docker-compose.yml / build.yml |
cpu |
perf_event_open |
✅ Oui |
docker-compose.desktop.yml |
itimer |
SIGPROF (JVM) | ❌ Non |
Les profils alloc (mémoire) et lock (contention verrou) sont actifs dans les deux modes.
Vérification¶
# Vérifier que Pyroscope reçoit des profils
curl "http://localhost:4040/api/apps"
# Attendu : liste contenant "perfshop.cpu"
Heap Dump¶
Accès¶
Le heap dump est accessible directement via la page de monitoring :
| Environnement | URL |
|---|---|
| Production | https://perfshop-monitoring.perfshop.io/heapdump-widget.html |
| Local | http://localhost:3001/heapdump-widget.html |
Un bouton ⬇️ Générer Heap Dump (.hprof) est également présent dans l'onglet Backend de la page monitoring, juste au-dessus de la section "Anomalies Chaos Backend".
Fonctionnement¶
Navigateur
└── GET /heapdump-widget.html ──► perfshop-monitoring (server.js)
└── Bouton → GET /api/heapdump ──► perfshop-monitoring (proxy)
└── GET perfshop-app:9090/actuator/heapdump ──► Spring Boot
└── Stream .hprof ──► téléchargement navigateur (~30s)
Le port 9090 est le management.server.port Spring Boot — interne au réseau Docker,
non accessible depuis l'hôte. Le proxy server.js est nécessaire.
Activation Spring Boot¶
Dans application.yml :
Analyse du fichier .hprof¶
| Outil | Usage |
|---|---|
| Eclipse MAT | Analyse approfondie — leak suspects, dominator tree, OQL |
| VisualVM | Visualisation rapide — heap summary, instances par classe |
Cas d'usage pédagogique
Le heap dump est l'outil de référence pour diagnostiquer F3 OutOfMemoryError :
activer le chaos fonctionnel niveau Expert, générer du trafic, puis capturer le heap dump.
Dans Eclipse MAT, chercher byte[] dans le dominator tree — les allocations massives
de FunctionalChaosService.applyF3CatalogOom sont immédiatement visibles.
Dashboard APM Formateur¶
Fichier : grafana/dashboards/dashboard-apm-formateur.json
UID : perfshop-apm-formateur
Sections¶
| Ligne | Contenu | Datasource |
|---|---|---|
| 🔍 Traces Distribuées | Traces/min, latence P95 /orders, erreurs 5xx, heap JVM, niveau chaos | Prometheus |
| 📈 Latences & Taux d’erreur | P50/P95/P99 toutes routes, taux d’erreur par opération | Prometheus |
| 🔎 Explorateur de Traces | Traces admin (X-Admin-Token), traces SQL (db.statement), toutes traces | Tempo |
| 🔥 Profiling CPU | Flamegraph perf_event (Linux/NAS) + flamegraph itimer (Docker Desktop) | Pyroscope |
| 🔥 Lock Contention | Flamegraph contention verrou JVM (A8 race condition) | Pyroscope |
| 🔥 Heap Flamegraph | Allocations mémoire massives (F3-OOM) | Pyroscope |
| 🧡 JVM Détail | Heap used/committed/max, threads live/daemon/peak | Prometheus |
| 🧹 Heap Dump | Bouton téléchargement .hprof via monitoring proxy | HTML |
Deux flamegraphs CPU côte à côte
Le panel CPU est dédoublé : un panel utilise process_cpu:cpu:nanoseconds (perf_event —
Linux/NAS), l’autre process_cpu:samples:count (itimer — Docker Desktop).
Selon l’environnement, l’un aura des données et l’autre sera vide (« No Data »).
Les titres des panels l’indiquent explicitement.
Panel Traces récentes — détail technique¶
{
"type": "table",
"targets": [{
"queryType": "traceql",
"query": "{}",
"datasource": { "type": "tempo", "uid": "tempo" }
}]
}
Pourquoi type: table et pas type: traces ?
Le plugin natif traces de Grafana 12 appelle /api/v2/search (Tempo 2.5+).
Tempo 2.4.2 ne supporte que /api/search (v1), accessible via queryType: "traceql".
Le panel table reçoit bien les données — 40 traces confirmées dans le Query Inspector.
Chaque ligne est cliquable et ouvre le détail de la trace dans Explore.
Reconstruction après modification¶
Agents (changement de version)¶
Les agents sont embarqués dans l'image Docker. Un rebuild est nécessaire :
# Sur le NAS
cd /volume4/docker-speed/perfshop
docker compose -f docker-compose.build.yml build perfshop-app
docker save perfshop-app:latest | gzip > /tmp/perfshop-app.tar.gz
# ... déploiement habituel