Platform logo

JetBrains Platform

Plugin and extension development for JetBrains products.

All Things Web Backstage Development GoLand IntelliJ IDEA IntelliJ Platform Plugin Highlights Plugins PyCharm Research Rider WebStorm

Dans les coulisses : comment le plugin OpenTelemetry cartographie vos microservices en temps réel

Read this post in other languages:

Nous sommes tous passés par là : on rejoint un nouveau projet, et la première chose que l’on demande, c’est le schéma d’architecture. On reçoit un schéma qui semble irréprochable, mais après une semaine de débogage, on s’aperçoit qu’il date déjà de six mois. Le service A n’a pas communiqué avec le service B depuis le printemps, et il y a une nouvelle file d’attente de messages que personne n’a pris la peine de documenter.

Comprendre comment un système complexe s’articule réellement est un casse-tête classique en ingénierie. Vous pouvez essayer de le comprendre manuellement (si vous avez confiance en vos capacités et suffisamment de temps devant vous), ou utiliser l’analyse statique pour explorer la base de code (qui ne permet souvent pas de déterminer comment les services sont réellement interconnectés lors de l’exécution).

Mais il existe une troisième voie : l’analyse dynamique. Et si on pouvait simplement observer le système en fonctionnement et établir le schéma à partir de ce qui se passe réellement ?

Comme le plugin OpenTelemetry collecte déjà une grande quantité de données sur l’exécution (journaux, métriques et traces), nous nous sommes rendu compte que nous avions là une occasion idéale de générer automatiquement cette cartographie de l’architecture pour vous. Voici un aperçu du fonctionnement interne de la fonctionnalité Service Map, développée dans le cadre d’une collaboration entre les équipes Rider Execution et Software Engineering Research.

L’ingrédient magique : les traces

Si le domaine de l’observabilité ne vous est pas inconnu, vous en connaissez sans doute les « trois piliers » : les journaux, les métriques et les traces.

Les journaux vous indiquent ce qui s’est passé, les métriques en quantifient l’ampleur, et les traces vous montrent le parcours d’une requête à travers votre système. Les traces sont constituées d’unités de travail individuelles appelées spans.

Comme OpenTelemetry standardise ces spans (en définissant explicitement, par exemple, les spans HTTP Client et HTTP Server), ils représentent le meilleur moyen de comprendre l’architecture d’un système. En s’appuyant sur le standard OpenTelemetry, le plugin peut visualiser votre système indépendamment de votre stack technologique, à condition que votre application et vos bibliothèques émettent des spans conformément aux attentes d’OTel.

La création d’une carte à partir des traces présente un avantage considérable : c’est la source de vérité sur ce qui se passe à l’exécution. Nous ne faisons pas de suppositions à partir du code source ou de spécifications obsolètes. Nous examinons les données générées par le système en cours d’exécution.

Comment cela fonctionne

Alors, comment cela fonctionne-t-il concrètement au sein de votre JetBrains IDE ?

Lorsque vous démarrez votre IDE avec le plugin OpenTelemetry activé, ce dernier lance un backend OpenTelemetry local léger, capable de traiter les données de télémétrie de votre application. 

Quand vous cliquez sur Run dans votre IDE : 

  1. Le plugin fournit à l’application les variables d’environnement OTel standard, afin qu’elle sache que les données doivent être envoyées au backend local.
  2. Votre application (déjà configurée pour émettre des spans) commence à envoyer des données de télémétrie à notre backend local.
  3. Le backend traite ces spans entrants de manière asynchrone, en construisant et en actualisant en continu un modèle interne de votre architecture.
  4. Lorsque vous cliquez sur l’onglet Service Map, le plugin OpenTelemetry récupère le dernier modèle structurel depuis le backend et affiche le diagramme visuel.

La réalité parfois chaotique des données de télémétrie

Quand on observe un schéma d’architecture, il paraît statique et ordonné. Mais le flux de données de télémétrie qui génère ce diagramme est tout sauf ordonné. Avant de pouvoir écrire un algorithme permettant de relier les différents éléments, nous avons dû résoudre plusieurs problèmes cachés :

Chaos sur le réseau 

Les spans arrivent de manière totalement indépendante, et leur ordre n’est jamais garanti. Un span parent peut se terminer et arriver après que son span enfant a déjà été traité.

Absence de ligne d’arrivée 

Une trace ne dit jamais explicitement « J’ai terminé ». À un instant donné, on ne peut jamais exclure à 100 % qu’un span en retard soit sur le point d’arriver.

Données utiles non typées

OpenTelemetry ne fournit pas de version strictement typée pour chaque type de span. Au lieu de cela, chaque span contient une map clé-valeur avec des attributs qui décrivent la sémantique de l’opération. Nous avons dû déduire le type d’interaction qu’ils représentaient uniquement en inspectant leurs attributs.

L’algorithme de reconstruction

Pour traiter ces données asynchrones qui arrivent dans le désordre, nous avons conçu la reconstruction d’architecture comme un algorithme de traitement de flux. Plutôt que de patienter jusqu’à avoir une trace complète (ce qui, comme nous venons de le voir, est impossible à garantir), nous traitons chaque span dès qu’il arrive.

Nous commençons par identifier ce que nous observons. Nous récupérons les métadonnées de base du span, puis nous examinons ses attributs sémantiques pour le classifier : des attributs comme http.request.method et http.response.status_code nous indiquent qu’il s’agit d’un appel HTTP, tandis que d’autres signalent une requête de base de données, une interaction avec une file d’attente de messages, et ainsi de suite.

Nous déterminons ensuite quel service l’a émis. Un nouveau service que nous n’avons pas vu ? On l’ajoute à la carte. Déjà présent ? Nous fusionnons les nouvelles données et mettons à jour ses statistiques.

Vient ensuite la partie intéressante : relier les différents éléments au-delà des frontières entre les services. Un appel HTTP entièrement instrumenté a deux côtés : le service appelant émet un span CLIENT, tandis que le service récepteur émet un span SERVER. Le contexte de la trace voyage avec la requête, de sorte que le span SERVER en aval est créé en tant qu’enfant du span CLIENT en amont.

Ainsi, lorsqu’un span HTTP Client sortant apparaît, nous cherchons son enfant côté serveur. Lorsqu’un span HTTP Server entrant apparaît, nous cherchons le parent qui l’a appelé. Si le span correspondant existe déjà dans notre système, nous traçons (ou mettons à jour) immédiatement la connexion entre les deux services. Si ce n’est pas le cas, nous gardons le span en mémoire en attendant l’arrivée de son autre moitié. 

D’autres types de dépendances nécessitent des règles légèrement différentes. L’appel à une base de données est généralement représenté par un seul span CLIENT, ce qui nous permet de déduire directement le nœud de base de données à partir de ses attributs sémantiques. Pour la messagerie, cela peut être plus varié : les opérations du producteur et du consommateur peuvent être liées par une relation parent-enfant ou par des liens entre spans, selon le système de messagerie et son instrumentation. Dans tous les cas, le backend traite les spans au fur et à mesure de leur arrivée et enrichit progressivement la carte à mesure que de nouveaux éléments deviennent disponibles.

C’est cette dernière étape qui permet au plugin de construire une carte précise en temps réel, même lorsque le réseau achemine les données tardivement et dans le désordre.

Carte des services montrant les communications HTTP entre services et l’accès à la base de données.

Cela nous permet de traiter et d’afficher des informations sur les requêtes HTTP, les requêtes de base de données et les files d’attente de messages.

Carte des services montrant les communications entre services via une file d’attente de messages (rabbit) et les accès à la base de données.

Comme la carte est construite à partir de spans OpenTelemetry standard et que l’algorithme de reconstruction s’appuie sur des conventions sémantiques plutôt que sur des API spécifiques à un framework, cette fonctionnalité est totalement indépendante du langage et du fournisseur. La même logique s’applique aux applications JVM, .NET, Python, Go et autres applications instrumentées avec OpenTelemetry, à condition que leur instrumentation émette les spans attendus et propage correctement le contexte. Cela signifie également que vous pouvez utiliser cette fonctionnalité dans le JetBrains IDE le plus adapté à votre pile technologique : IntelliJ IDEA, GoLand, PyCharm, WebStorm ou Rider.

Visualisez votre propre architecture

Vous voulez voir votre propre architecture cartographiée en temps réel ? Vous attendiez un seul appel HTTP ou une seule requête de base de données, mais le diagramme en affiche plusieurs ? Détecter ce type de problème dès la phase de développement vous laisse le temps de le corriger avant la publication de la version.

Vous pouvez installer le plugin OpenTelemetry dès maintenant pour ne plus avoir à deviner comment vos services communiquent entre eux.

 
Auteurs de l’article orignal en anglais :
Nikita Dukin

Nikita Dukin

Egor Klimov

Egor Klimov