Concepts en lien avec le suivi distribué .NET
Le suivi distribué est une technique de diagnostic permettant aux ingénieurs de localiser les défaillances et les problèmes de performances au sein des applications, en particulier celles qui pourraient être distribuées sur plusieurs ordinateurs ou processus. Consultez la vue d’ensemble du suivi distribué pour obtenir des informations générales sur les cas d’usage du suivi distribué.
Suivis et activités
Chaque fois qu’une nouvelle demande est reçue par une application, elle peut être associée à une trace. Dans les composants d’application écrits en .NET, les unités de travail d’une trace sont représentées par des instances de System.Diagnostics.Activity et la trace dans son ensemble forme une arborescence de ces activités, couvrant potentiellement de nombreux processus distincts. La première activité créée pour une nouvelle demande forme la racine de l’arborescence de trace et suit la durée globale et la réussite/l’échec de la demande. Les activités enfants peuvent éventuellement être créées pour subdiviser le travail en différentes étapes qui peuvent être suivies individuellement. Si l’on prend l’exemple d’une activité qui suit une requête HTTP entrante spécifique dans un serveur web, vous pouvez créer des activités enfants pour suivre chacune des requêtes de base de données nécessaires pour terminer la requête. Cela permet d’enregistrer la durée et la réussite de chaque requête indépendamment. Les activités peuvent enregistrer d’autres informations pour chaque unité de travail, telles que les OperationNamepaires nom-valeur appelées Tags et Events. Le nom identifie le type de travail effectué, les balises peuvent enregistrer des paramètres descriptifs du travail, et les événements sont un mécanisme de journalisation simple pour enregistrer les messages de diagnostic horodatés.
Notes
Dans le secteur, un autre nom commun pour les unités de travail dans une trace distribuée sont les « étendues ». .NET a adopté le terme « Activité » il y a de nombreuses années, avant que le nom « étendue » soit bien établi pour ce concept.
ID d'activité
Les relations parent-enfant entre les activités de l’arborescence de trace distribuée sont établies à l’aide d’ID uniques. L’implémentation .NET du suivi distribué prend en charge deux schémas d’ID : le standard W3C TraceContext, qui est la valeur par défaut dans .NET 5 et versions ultérieures, et une convention .NET plus ancienne appelée « Hiérarchique » disponible pour la compatibilité descendante. Activity.DefaultIdFormat contrôle le schéma d’ID utilisé. Dans le standard W3C TraceContext, chaque trace est affectée à un ID de trace de 16 octets globalement unique (Activity.TraceId), et chaque activité au sein de la trace reçoit un ID d’étendue unique de 8 octets (Activity.SpanId). Chaque activité enregistre l’ID de trace, son propre ID d’étendue et l’ID d’étendue de son parent (Activity.ParentSpanId). Étant donné que les traces distribuées peuvent suivre le travail entre les limites de processus, les activités parent et enfant peuvent ne pas se trouver dans le même processus. La combinaison d’un ID de trace et d’un ID d’étendue parent peut identifier de manière unique l’activité parente globalement, quel que soit le processus dans lequel elle réside.
Activity.DefaultIdFormat contrôle le format d’ID utilisé pour démarrer de nouvelles traces, mais par défaut, l’ajout d’une nouvelle activité à une trace existante utilise le format utilisé par l’activité parente. Le fait de définir Activity.ForceDefaultIdFormat sur true remplace ce comportement et crée toutes les nouvelles activités avec DefaultIdFormat, même lorsque le parent utilise un autre format d’ID.
Démarrer et arrêter des activités
Chaque thread d’un processus peut avoir un objet Activity correspondant qui suit le travail effectué sur ce thread, accessible via Activity.Current. L’activité actuelle circule automatiquement le long de tous les appels synchrones sur un thread et suit les appels asynchrones traités sur différents threads. Si l’activité A est l’activité actuelle sur un thread et que le code démarre une nouvelle activité B, B devient la nouvelle activité actuelle sur ce thread. Par défaut, l’activité B traite également l’activité A comme son parent. Lorsque l’activité B est arrêtée ultérieurement, l’activité A est restaurée en tant qu’activité active sur le thread. Quand une activité est démarrée, elle capture l’heure actuelle en tant que Activity.StartTimeUtc. Lorsqu’elle s’arrête, Activity.Duration est calculé comme la différence entre l’heure actuelle et l’heure de début.
Coordonner au-delà des limites de processus
Pour suivre le travail au-delà des limites de processus, les ID parents d’activité doivent être transmis sur le réseau afin que le processus de réception puisse créer des activités qui y font référence. Lorsque vous utilisez le format d’ID TraceContext W3C, .NET utilise également les en-têtes HTTP recommandés par le standard pour transmettre ces informations. Lorsque vous utilisez le format d’ID Hierarchical, .NET utilise un en-tête HTTP request-id personnalisé pour transmettre l’ID. Contrairement à de nombreux autres runtimes de langage, les bibliothèques .NET fournies telles que le serveur web ASP.NET et System.Net.Http en mode natif comprennent comment décoder et encoder des ID d’activité sur les messages HTTP. Le runtime comprend également comment transmettre l’ID via des appels synchrones et asynchrones. Cela signifie que les applications .NET qui reçoivent et émettent des messages HTTP participent automatiquement aux ID de trace distribuée transmis, sans codage spécial par le développeur de l’application ou les dépendances de bibliothèque tierce. Les bibliothèques tierces peuvent ajouter la prise en charge de la transmission d’ID sur des protocoles de messages non-HTTP ou prendre en charge des conventions d’encodage personnalisées pour HTTP.
Collecter des traces
Le code instrumenté peut créer des objets Activity dans le cadre d’une trace distribuée, mais les informations contenues dans ces objets doivent être transmises et sérialisées dans un magasin persistant centralisé afin que la trace entière puisse être examinée plus tard. Il existe plusieurs bibliothèques de collecte de données de télémétrie qui peuvent effectuer cette tâche, comme Application Insights, OpenTelemetry ou une bibliothèque fournie par un fournisseur de télémétrie tiers ou APM. Les développeurs peuvent également créer leur propre collecte de données de télémétrie Activity personnalisée en utilisant System.Diagnostics.ActivityListener ou System.Diagnostics.DiagnosticListener. ActivityListener prend en charge l’observation de n’importe quelle activité, que le développeur ait ou non des connaissances préalables sur celle-ci. Cela rend ActivityListener une solution simple et flexible à usage général. En revanche, l’utilisation de DiagnosticListener est un scénario plus complexe qui exige que le code instrumenté soit choisi en appelant DiagnosticSource.StartActivity et que la bibliothèque de collection connaisse les informations d’affectation de noms exactes utilisées par le code instrumenté au démarrage. L’utilisation de DiagnosticSource et de DiagnosticListener permet au créateur et à l’écouteur d’échanger des objets .NET arbitraires et d’établir des conventions de transmission d’informations personnalisées.
échantillonnage
Pour améliorer les performances dans les applications à débit élevé, le suivi distribué sur .NET prend en charge l’échantillonnage uniquement d’un sous-ensemble de traces plutôt que de tout enregistrer. Pour les activités créées avec l’API ActivitySource.StartActivity recommandée, les bibliothèques de collecte de télémétrie peuvent contrôler l’échantillonnage avec le rappel ActivityListener.Sample. La bibliothèque de journalisation peut choisir de ne pas créer l’activité du tout, de la créer avec des informations minimales nécessaires pour propager la distribution des ID de suivi ou de la remplir avec des informations de diagnostic complètes. Ces choix remplacent l’augmentation de la surcharge des performances par l’augmentation de l’utilité du diagnostic. Les activités qui ont commencé à utiliser l’ancien modèle d’appel de Activity.Activity et DiagnosticSource.StartActivity peuvent également prendre en charge l’échantillonnage DiagnosticListener en appelant d’abord DiagnosticSource.IsEnabled. Même lors de la capture d’informations de diagnostic complètes, l’implémentation .NET est conçue pour être rapidement couplée à un collecteur efficace et une activité peut être créée, remplie et transmise en environ une microseconde sur du matériel moderne. L’échantillonnage peut réduire le coût d’instrumentation à moins de 100 nanosecondes pour chaque activité qui n’est pas enregistrée.
Étapes suivantes
Pour obtenir un exemple de code permettant de commencer à utiliser le suivi distribué dans les applications .NET, consultez la page sur l’instrumentation du suivi distribué.