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

  1. 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)
  2. Il est inclus dans l’en-tête HTTP X-Correlation-ID
  3. 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
  4. 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 :

OutilTypeCaractéristiques
JaegerOpen sourceVisualisation des traces, analyse de la latence
ZipkinOpen sourceLéger, bonne intégration avec Spring
OpenTelemetryStandardVendor-neutral, combine traces, métriques et logs
AWS X-RayManagedIntégré aux services AWS
Datadog APMSaaSTraces + 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 :

ChampDescription
timestampInstant exact (ISO 8601 avec timezone)
levelSévérité (DEBUG, INFO, WARN, ERROR)
serviceNom du service qui génère le log
correlationIdID de corrélation de l’opération
traceIdID de la trace distribuée
spanIdID du span actuel
messageDescription lisible de l’événement
contextDonné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

  1. Obtenir le correlation ID de la commande (depuis le frontend ou les logs du BFF)
  2. Rechercher tous les logs correspondant à ce correlation ID
  3. Visualiser la trace distribuée
  4. Identifier où le flux s’est interrompu :
    • L’événement OrderPlaced a-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é ?

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.