đ¶ Partie 6 : Projet Pratique (Full Stack)
Cas d'usage : Dépanner une application E-commerce (React + Python + K8s) en corrélant RUM, Traces, Métriques et Logs.
Objectif & Scénario
L'alerte se déclenche : "Les clients se plaignent que le checkout est LENT !"
Projet AlerteArchitecture de l'App Fictive
Notre stack : React (RUM), Python (APM), Postgres (Metrics), K8s (Agent).
Architecture React PythonConfiguration (Le Tagging Unifié)
Le setup (RUM, APM, K8s) qui rend la corrélation (service, env) possible.
Ătape 1 : L'EnquĂȘte (RUM)
Pivot depuis le Frontend. (click on #btn-checkout > 8000ms). Isoler le fetch.
Ătape 2 : L'EnquĂȘte (APM)
Pivot vers le Backend (Flame Graph). Isoler le Span postgres.query (7.2s).
Ătape 3 : L'EnquĂȘte (Logs)
Pivot vers les Logs (trace_id). Confirmer le INSERT lent (WARN).
Ătape 4 : L'EnquĂȘte (MĂ©triques)
Pivot vers la DB (service:db-postgres). Trouver le pic de postgresql.locks.
Conclusion de l'EnquĂȘte
La cause racine (Root Cause) : Un access_exclusive_lock (d'un batch) bloque les INSERT.
Cheat-sheet (L'EnquĂȘte)
Le workflow de pivot : RUM -> APM -> LOGS -> METRICS.
cheat M-T-L-RL'Objectif : L'EnquĂȘte Full-Stack
Ce projet fictif simule le scénario le plus courant (et le plus stressant) : **"Les clients se plaignent que le site est lent !"**
Notre objectif est de trouver la **cause racine (root cause)** en utilisant les 4 piliers de DataDog (RUM, Métriques, Traces, Logs), en pivotant de l'un à l'autre grùce au **Tagging Unifié**.
Le Scénario : L'Alerte (Monitor)
10:30 AM : Une alerte (Monitor DataDog) se déclenche dans Slack :
[ALERTE đš] P95 Checkout Latency > 8s
(Triggered)
avg(last_5m):rum.action.loading_time{env:prod, action.name:"click on #btn-checkout"} > 8000ms
(Current value: 8530ms)
Traduction : La latence p95 (ressentie par l'utilisateur) lors d'un clic sur le bouton "Payer" est supérieure à 8 secondes. C'est catastrophique.
L'Application (sur K8s, env:prod)
| Composant | Technologie | Service (Tag) | Monitoring DataDog |
|---|---|---|---|
| Frontend | React (Navigateur) | service:web-store | RUM (@datadog/browser-rum) |
| API (Backend) | Python (Flask) | service:api-payment | APM (dd-trace-py) + Logs (stdout) |
| Database | PostgreSQL | service:db-postgres-primary | Metrics (Intégration) + Logs (File) |
| Infrastructure | Kubernetes | (K8s) | Agent (DaemonSet) (Metrics Host + Logs stdout) |
Diagramme d'Architecture & Observabilité
(Utilisateur: Navigateur)
+-------------------------+
| App React (Client) | --(RUM SDK)--> [DataDog SaaS]
| (service: web-store) |
+-------------------------+
| (fetch /api/checkout)
| (Injecte x-datadog-trace-id)
âŒ
(Cluster Kubernetes: env:prod)
+-------------------------------------------------------------+
| |
| +-----------------------+ +---------------------------+ |
| | Pod API (Python/Flask) | | Pod DB (Postgres) | |
| | (service: api-payment)| | (service: db-postgres) | |
| | (Logs -> stdout) | | (Logs -> /var/log/...) | |
| +-----------------------+ +---------------------------+ |
| | (APM: dd-trace-py) | | | |
| +-----------------------+ +---------------------------+ |
| | (Logs) | (Logs, Metrics) |
| +-----------------------------+ |
| | |
| +---------------------------------------------------------+ |
| | Pod Agent DataDog (DaemonSet, 1 par NĆud) | |
| | (Collecte stdout, /var/log, APM 8126, DogStatsD 8125) | |
| +---------------------------------------------------------+ |
| | (HTTPS: Métriques, Logs, Traces) |
| ⌠|
+-------------+---------------------------------------------+
|
âŒ
[DataDog SaaS (UI)]
(Dashboards, APM, Logs, RUM)
Pour que ce scĂ©nario fonctionne, la configuration (le **Tagging**) doit ĂȘtre parfaite (env:prod, service:...).
Frontend : RUM (React index.js)
// (index.js de l'app React)
import { datadogRum } from '@datadog/browser-rum';
datadogRum.init({
applicationId: '...',
clientToken: '...',
site: 'datadoghq.eu',
// (Tags unifiés)
service: 'web-store',
env: 'production',
version: '2.1.0',
// (Active la corrélation RUM <-> APM)
allowedTracingOrigins: ["https://api.mon-shop.com"]
});
Backend : APM (Python Dockerfile)
# (Dockerfile de l'API Python)
FROM python:3.10-slim
RUN pip install dd-trace gunicorn
# (Définir les Tags (via Env Vars))
ENV DD_ENV="production"
ENV DD_SERVICE="api-payment"
ENV DD_VERSION="1.2.0"
ENV DD_LOGS_INJECTION="true" # (Injecte le trace_id dans les logs JSON !)
# (Lancer via dd-trace-run)
CMD ["dd-trace-run", "gunicorn", "app:main"]
Infra : K8s (Annotations Autodiscovery)
# (deployment-postgres.yaml)
apiVersion: apps/v1
kind: Deployment
spec:
template:
metadata:
annotations:
# (Autodiscovery pour les Métriques)
"ad.datadoghq.com/db-container.checks": |
{
"postgres": {
"instances": [
{
"host": "%%host%%",
"port": 5432,
"tags": ["env:production", "service:db-postgres-primary"]
}
]
}
}
# (Autodiscovery pour les Logs)
"ad.datadoghq.com/db-container.logs": |
[
{"source": "postgresql", "service": "db-postgres-primary"}
]
spec:
containers:
- name: db-container
image: postgres:15
Nous allons dans RUM > Performance > Actions et nous cliquons sur l'action click on #btn-checkout.
Le dashboard RUM confirme que l'action est lente (8000ms). Il décompose cette latence :
- Frontend (JS) : 50ms (Le JS React est rapide).
- Backend (Réseau) : 7950ms (Le goulot d'étranglement est cÎté serveur).
Nous cliquons sur l'onglet "Resources" (Ressources) de cette action RUM. Nous voyons la requĂȘte rĂ©seau coupable : POST https://api.mon-shop.com/api/v1/checkout (DurĂ©e: 7950ms)
GrĂące Ă la corrĂ©lation RUM <-> APM (configurĂ©e en 6.3), nous voyons un bouton "View Trace" (Voir la Trace) Ă cĂŽtĂ© de cette requĂȘte.
Pivot : RUM -> APM
En cliquant sur "View Trace", nous pivotons de RUM (Frontend) vers **APM (Backend)**. DataDog nous montre le Flame Graph (diagramme en cascade) de *cette* requĂȘte spĂ©cifique (trace_id: abc-123).
Diagramme (Flame Graph APM)
Service: web-store (RUM) (8000ms)
|
+--- Service: api-payment (Python/Flask) (7950ms) --------------------------------+
| | |
| +-- flask.request (Span) ------------------------------------------------+ |
| | | | |
| | +-- flask.auth (Span) (50ms) | |
| | | | |
| | +-- (Temps "inconnu" : 300ms) | |
| | | | |
| | +-- api.payment.charge (Span Custom) (7500ms) ---------------------+ | |
| | | | | | |
| | | +-- http.request (Stripe API) (Span) (200ms) | | |
| | | | | | |
| | | +-- (Temps "inconnu" : 100ms) | | |
| | | | | | |
| | | +-- postgres.query (Span) (7200ms) --------------------------+ | | |
| | | | | | |
| | | +-------------------------------------------------------------+ | |
| | | | |
| | +-- db.commit (Span) (50ms) | |
| | | |
| +-----------------------------------------------------------------------+ |
| |
+------------------------------------------------------------------------------+
Diagnostic : La latence (7950ms) ne vient pas de l'API de paiement Stripe (200ms). Elle vient de notre propre base de données. Un postgres.query (dans notre Span custom api.payment.charge) prend **7.2 secondes**.
Pivot : APM -> Logs
Nous cliquons sur le Span postgres.query (7200ms).
Dans le panneau du Span, l'auto-instrumentation (dd-trace-py) nous montre le Tag db.statement : INSERT INTO orders (user_id, item, ...) VALUES (...)
Un INSERT ne devrait jamais prendre 7 secondes. Nous cliquons sur l'onglet **"Logs"** (qui est automatiquement filtré sur trace_id: abc-123 grùce à DD_LOGS_INJECTION=true).
Logs corrélés (Filtrés sur trace_id: abc-123)
(service: api-payment) INFO: User 456 checkout initiated. [dd.trace_id=abc-123]
(service: api-payment) INFO: Calling Stripe API... [dd.trace_id=abc-123]
(service: api-payment) INFO: Stripe call successful (200ms). [dd.trace_id=abc-123]
(service: api-payment) WARN: Slow query detected (7200ms) for statement: INSERT INTO orders... [dd.trace_id=abc-123]
(service: api-payment) INFO: Checkout for user 456 complete. [dd.trace_id=abc-123]
Diagnostic : Les logs confirment que l'INSERT est lent. Il n'y a pas d'ERROR, juste un WARN (que nous avons logué). Pourquoi un INSERT est-il si lent ? C'est probablement un **verrou (LOCK)**.
Pivot : Logs -> Métriques
Nous pivotons vers l'infrastructure. Nous cliquons sur le Tag service:db-postgres-primary (qui était sur le Span/Log). DataDog nous amÚne au **Dashboard de l'Intégration Postgres**.
Nous regardons les métriques de la base de données (collectées par l'Agent, configuré en 6.3) au moment de l'incident :
postgresql.cpu.total: Normal (20%)postgresql.connections: Normal (30/100)postgresql.locks(groupé parlock_mode) :
Widget (Timeseries) : sum:postgresql.locks{*} by {lock_mode}
(Graphique)
|
100 |
|
50 |
|
0 |_____________________________^_____________________________
|
(Légende)
- access_share_lock: 30
- row_exclusive_lock: 10
- access_exclusive_lock: 45 (-> PIC ANORMAL !)
BINGO. Un pic de verrous access_exclusive_lock coĂŻncide parfaitement avec la latence.
Pivot : Métriques -> Cause Racine
Le RUM nous a dit que les utilisateurs (Frontend) souffraient (8s).
L'APM (Trace) a isolé le problÚme sur le Backend (api-payment).
L'APM (Span) a ciblĂ© une requĂȘte INSERT spĂ©cifique (7.2s).
Les Logs (corrĂ©lĂ©s) ont confirmĂ© que cette requĂȘte Ă©tait lente, mais sans erreur.
Les Métriques (DB) ont montré la cause racine : un pic de verrous access_exclusive_lock sur Postgres.
Action (Cause Racine)
Un autre service (ex: service:reporting-batch) doit lancer un TRUNCATE ou VACUUM FULL (qui prend un verrou exclusif) sur la table orders en pleine journée (env:prod), bloquant tous les INSERT du checkout.
Sans cette corrĂ©lation M-T-L-R, le Frontend aurait blĂąmĂ© le Backend, et le Backend aurait blĂąmĂ© la DB. Avec DataDog, l'Ă©quipe SRE sait exactement quel job batch (service:reporting-batch) doit ĂȘtre dĂ©placĂ© pendant la nuit.
C'est le "workflow" mental pour dépanner n'importe quel problÚme dans une stack moderne avec DataDog.
| Ătape | Produit DataDog | Question | Action |
|---|---|---|---|
| 1 | Monitors (Alerte) | "Qu'est-ce qui est cassé ?" | (Notification Slack/PagerDuty) |
| 2 | RUM (Frontend) | "Est-ce que l'utilisateur est impacté ? Est-ce le Frontend ou le Backend ?" | (Isoler la Resource (fetch) lente) |
| 3 | APM (Backend) | "OĂč (dans le backend) est la latence ?" | (Suivre la Trace, trouver le Span lent (ex: db.query)) |
| 4 | Logs (Détails) | "Y a-t-il une erreur ou un contexte pour ce Span ?" | (Pivoter vers les Logs (trace_id), lire le WARN/ERROR) |
| 5 | Metrics (Infra) | "L'infrastructure (DB, Host) est-elle la cause ?" | (Pivoter vers le Dashboard (service:db), trouver le pic postgresql.locks) |
