Aller au contenu

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 :

docker compose stop perfshop-tempo
docker compose rm -f perfshop-tempo
docker volume rm perfshop_tempo-data
docker compose up -d --no-deps perfshop-tempo


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 :

management:
  endpoints:
    web:
      exposure:
        include: health,info,metrics,prometheus,heapdump

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

Dashboard (modification JSON)

# Recharger sans rebuild
curl -s -X DELETE http://admin:perfshop@localhost:3002/api/dashboards/uid/perfshop-apm-formateur
curl -s -X POST http://admin:perfshop@localhost:3002/api/admin/provisioning/dashboards/reload