Traçabilité
La traçabilité dans les systèmes distribués : correlation IDs, tracing distribué et logging structuré pour suivre le parcours de chaque opération entre les services.
Pourquoi la traçabilité est essentielle
Dans un monolithe, suivre le déroulement d’une opération est relativement simple : tout se passe dans le même processus, avec un journal unique. Dans un système distribué, une seule action de l’utilisateur peut traverser 5 services ou plus, chacun avec ses propres logs, ses temps d’exécution et ses défaillances possibles.
Sans traçabilité, diagnostiquer un problème revient à chercher une aiguille dans une botte de foin distribuée. La traçabilité permet de reconstruire le parcours complet d’une opération à travers tous les services impliqués.
Les trois piliers de la traçabilité
1. Correlation ID
Un identifiant unique qui accompagne une opération depuis son origine jusqu’au dernier service qui la traite. Tous les logs, événements et métriques liés à cette opération partagent le même correlation ID.
2. Distributed Tracing
Un système qui enregistre le temps et la relation entre les opérations dans chaque service, permettant de visualiser le déroulement complet sous forme d’un arbre de spans.
3. Logging structuré
Des logs au format structuré (JSON) qui incluent le correlation ID et des métadonnées contextuelles, facilitant la recherche et la corrélation.
Le Correlation ID en action
sequenceDiagram
participant FE as Frontend
participant GW as API Gateway
participant BFF as BFF
participant MS1 as ms-orders
participant MS2 as ms-inventory
participant EB as Event Bus
FE->>GW: POST /orders (X-Correlation-ID: abc-123)
GW->>BFF: Forward (X-Correlation-ID: abc-123)
BFF->>MS1: Crear orden (X-Correlation-ID: abc-123)
MS1->>EB: OrderPlaced (correlationId: abc-123)
EB->>MS2: OrderPlaced (correlationId: abc-123)
MS2->>MS2: Reservar stock (log: abc-123)
Comment le Correlation ID se propage
- Le frontend génère un UUID unique au démarrage de l’opération (ou l’API Gateway le génère s’il n’est pas fourni)
- Il est inclus dans l’en-tête HTTP
X-Correlation-ID - Chaque service l’extrait de la requête entrante et l’inclut dans :
- Tous ses logs
- Tous les appels HTTP sortants
- Tous les événements qu’il publie sur l’Event Bus
- Toutes les métriques qu’il enregistre
- Les consommateurs d’événements l’extraient du payload de l’événement
Règle fondamentale
Ne jamais générer un nouveau correlation ID dans un service intermédiaire. Si un service reçoit une requête sans correlation ID, il peut en générer un. Mais s’il en existe déjà un, il doit le propager tel quel.
Distributed Tracing
Le tracing distribué va au-delà du correlation ID. Il enregistre la structure temporelle du flux : quel service a appelé quel autre, combien de temps a duré chaque opération et où une erreur s’est produite.
Concepts clés
Trace : représente le déroulement complet d’une opération, de l’origine jusqu’à la fin. Une trace contient plusieurs spans.
Span : représente une opération individuelle au sein d’un service. Elle a un début, une fin, un nom et des métadonnées.
Parent-Child : les spans s’organisent en arbre. Le span du BFF est le parent du span du microservice qu’il invoque.
Exemple d’une trace
Trace: abc-123
├── [Gateway] POST /orders (5ms)
│ └── [BFF] createOrder (45ms)
│ ├── [ms-orders] createOrder (30ms)
│ │ └── [DB] INSERT INTO orders (8ms)
│ └── [ms-orders] publishEvent (5ms)
└── [ms-inventory] handleOrderPlaced (20ms) ← asíncrono
└── [DB] UPDATE stock (6ms)
Cette trace montre que :
- La requête totale a duré 50ms (Gateway → BFF → ms-orders)
- L’opération de base de données dans ms-orders a duré 8ms
- Le traitement asynchrone dans l’inventaire a pris 20ms supplémentaires
Outils de tracing
Les outils les plus courants pour le tracing distribué sont :
| Outil | Type | Caractéristiques |
|---|---|---|
| Jaeger | Open source | Visualisation des traces, analyse de la latence |
| Zipkin | Open source | Léger, bonne intégration avec Spring |
| OpenTelemetry | Standard | Vendor-neutral, combine traces, métriques et logs |
| AWS X-Ray | Managed | Intégré aux services AWS |
| Datadog APM | SaaS | Traces + métriques + logs sur une seule plateforme |
OpenTelemetry est en train de devenir le standard de facto car il est vendor-neutral et permet de changer d’outil sans modifier le code d’instrumentation.
Logging structuré
Pourquoi des logs structurés
Les logs en texte brut sont difficiles à rechercher et à corréler :
2024-01-15 10:30:00 INFO Order created successfully for customer 789
Les logs structurés en JSON permettent des recherches précises :
{
"timestamp": "2024-01-15T10:30:00Z",
"level": "INFO",
"service": "ms-orders",
"correlationId": "abc-123",
"traceId": "trace-456",
"spanId": "span-789",
"message": "Order created successfully",
"context": {
"orderId": "order-456",
"customerId": "cust-789",
"totalAmount": 150.00
}
}
Champs standard dans chaque log
Tous les services doivent inclure ces champs dans chaque entrée de log :
| Champ | Description |
|---|---|
timestamp | Instant exact (ISO 8601 avec timezone) |
level | Sévérité (DEBUG, INFO, WARN, ERROR) |
service | Nom du service qui génère le log |
correlationId | ID de corrélation de l’opération |
traceId | ID de la trace distribuée |
spanId | ID du span actuel |
message | Description lisible de l’événement |
context | Données supplémentaires pertinentes |
Centralisation des logs
Dans un système distribué, les logs de chaque service doivent être envoyés vers un système centralisé où ils peuvent être recherchés et corrélés :
graph LR
MS1[ms-orders] --> AGG[Log Aggregator]
MS2[ms-inventory] --> AGG
MS3[ms-payments] --> AGG
BFF[BFF] --> AGG
AGG --> STORE[Elasticsearch / CloudWatch / Loki]
STORE --> UI[Kibana / Grafana]
La traçabilité dans les flux asynchrones
La traçabilité dans les flux asynchrones est plus complexe car il n’y a pas de connexion HTTP directe entre le producteur et le consommateur de l’événement.
Propagation via les événements
Le correlation ID et le trace ID doivent être inclus dans le payload de l’événement :
{
"type": "OrderPlaced",
"metadata": {
"correlationId": "abc-123",
"traceId": "trace-456",
"parentSpanId": "span-789",
"timestamp": "2024-01-15T10:30:00Z",
"source": "ms-orders"
},
"payload": { ... }
}
Lorsque le consommateur traite l’événement, il crée un nouveau span enfant du span d’origine, préservant ainsi la chaîne de traçabilité.
Défi : la latence entre publication et consommation
Dans les flux asynchrones, du temps peut s’écouler entre la publication et la consommation. La trace peut afficher un écart temporel qui est normal et attendu.
Diagnostic des problèmes grâce à la traçabilité
Scénario : l’utilisateur signale que sa commande n’a pas été confirmée
- Obtenir le correlation ID de la commande (depuis le frontend ou les logs du BFF)
- Rechercher tous les logs correspondant à ce correlation ID
- Visualiser la trace distribuée
- Identifier où le flux s’est interrompu :
- L’événement
OrderPlaceda-t-il été publié ? - Le service d’inventaire l’a-t-il reçu ?
- Y a-t-il eu une erreur pendant le traitement ?
- L’événement de réponse a-t-il été publié ?
- L’événement
Sans traçabilité, ce diagnostic exigerait de passer en revue manuellement les logs de chaque service, en cherchant par timestamp et en espérant trouver quelque chose de pertinent.
Résumé
La traçabilité est ce qui rend un système distribué opérable. Le correlation ID relie toutes les opérations d’un flux, le tracing distribué montre la structure temporelle et les dépendances, et le logging structuré permet de rechercher et de corréler de manière efficace. Sans ces trois piliers, diagnostiquer des problèmes en production devient une tâche quasiment impossible.