Concepten voor gedistribueerde tracering van .NET
Gedistribueerde tracering is een diagnostische techniek waarmee technici fouten en prestatieproblemen in toepassingen kunnen lokaliseren, met name die welke kunnen worden gedistribueerd over meerdere machines of processen. Zie het overzicht van gedistribueerde tracering voor algemene informatie over waar gedistribueerde tracering nuttig is.
Traceringen en activiteiten
Telkens wanneer een nieuwe aanvraag wordt ontvangen door een toepassing, kan deze worden gekoppeld aan een tracering. In toepassingsonderdelen die zijn geschreven in .NET, worden werkeenheden in een trace vertegenwoordigd door exemplaren van System.Diagnostics.Activity en vormt de tracering als geheel een structuur van deze activiteiten, mogelijk verspreid over veel verschillende processen. De eerste activiteit die is gemaakt voor een nieuwe aanvraag vormt de hoofdmap van de traceringsstructuur en houdt de totale duur en geslaagde/mislukte verwerking van de aanvraag bij. Kinderactiviteiten kunnen optioneel worden gemaakt om het werk onder te verdelen in verschillende stappen die afzonderlijk kunnen worden bijgehouden. Bijvoorbeeld, op basis van een activiteit die een specifieke binnenkomende HTTP-aanvraag in een webserver heeft bijgehouden, kunnen onderliggende activiteiten worden gemaakt om elk van de databasequery's bij te houden die nodig waren om de aanvraag te voltooien. Hierdoor kan de duur en het succes van elke query onafhankelijk worden vastgelegd. Activiteiten kunnen andere gegevens vastleggen voor elke werkeenheid, zoals OperationName, naam-waardeparen genaamd Tagsen Events. De naam identificeert het type werk dat wordt uitgevoerd, tags kunnen beschrijvende parameters van het werk vastleggen en gebeurtenissen zijn een eenvoudig mechanisme voor logboekregistratie om tijdgebonden diagnostische berichten vast te leggen.
Notitie
Een andere algemene branchenaam voor werkeenheden in een gedistribueerde tracering zijn 'Spans'. .NET heeft de term 'Activiteit' vele jaren geleden aangenomen, voordat de naam 'Span' goed tot stand is gebracht voor dit concept.
Activiteit-ID's
Parent-Child relaties tussen activiteiten in de gedistribueerde traceringsstructuur worden ingesteld met behulp van unieke id's. . De implementatie van gedistribueerde tracering van NET ondersteunt twee id-schema's: de W3C-standaard TraceContext, wat de standaardinstelling is in .NET 5+ en een oudere .NET-conventie genaamd 'Hierarchical' die beschikbaar is voor achterwaartse compatibiliteit. Activity.DefaultIdFormat bepaalt welk id-schema wordt gebruikt. In de W3C TraceContext-standaard wordt aan elke tracering een wereldwijd unieke trace-id van 16 byte (Activity.TraceId) toegewezen en aan elke activiteit binnen de trace wordt een unieke span-id van 8 bytes (Activity.SpanId) toegewezen. Elke activiteit registreert de trace-id, de eigen span-id en de span-id van de bovenliggende activiteit (Activity.ParentSpanId). Omdat gedistribueerde traceringen werk over procesgrenzen heen kunnen volgen, bevinden zich bovenliggende en onderliggende activiteiten mogelijk niet in hetzelfde proces. De combinatie van een trace-id en een ouder span-id kan de bovenliggende activiteit wereldwijd uniek identificeren, ongeacht in welk proces deze zich bevindt.
Activity.DefaultIdFormat bepaalt welke id-indeling wordt gebruikt voor het starten van nieuwe traceringen, maar het toevoegen van een nieuwe activiteit aan een bestaande tracering maakt standaard gebruik van de indeling die de bovenliggende activiteit gebruikt. Als u Activity.ForceDefaultIdFormat instelt op true, wordt dit gedrag overschreven en worden alle nieuwe activiteiten gemaakt met de DefaultIdFormat, zelfs wanneer het bovenliggende item een andere id-indeling gebruikt.
Activiteiten starten en stoppen
Elke thread in een proces kan een bijbehorend activiteitsobject hebben waarmee het werk op die thread wordt bijgehouden, dat toegankelijk is via Activity.Current. De huidige activiteit loopt automatisch door alle synchrone aanroepen op een thread en volgt asynchrone aanroepen die op verschillende threads worden verwerkt. Als Activiteit A de huidige activiteit op een thread is en code een nieuwe activiteit B start, wordt B de nieuwe huidige activiteit op die thread. Standaard behandelt activiteit B activiteit A ook als de bovenliggende activiteit. Wanneer activiteit B later wordt gestopt, wordt activiteit A hersteld als de huidige activiteit op de thread. Wanneer een activiteit wordt gestart, wordt de huidige tijd vastgelegd als de Activity.StartTimeUtc. Wanneer het stopt, wordt Activity.Duration berekend als het verschil tussen de huidige tijd en de begintijd.
Coördinaat over procesgrenzen
Om werk over procesgrenzen bij te houden, moeten bovenliggende activiteit-ID's via het netwerk worden verzonden, zodat het ontvangende proces Activiteiten kan maken die naar deze ID's verwijzen. Wanneer u de W3C TraceContext ID-indeling gebruikt, gebruikt .NET ook de HTTP-headers die door de standaard aanbevolen zijn voor het verzenden van deze informatie. Wanneer u het formaat Hierarchical ID gebruikt, gebruikt .NET een aangepaste aanvraag-ID HTTP-header om de ID te verzenden. In tegenstelling tot veel andere taalruntimes, begrijpen .NET-bibliotheken zoals de ASP.NET webserver en System.Net.Http op natuurlijke wijze hoe ze activiteits-id's op HTTP-berichten moeten decoderen en coderen. De runtime begrijpt ook hoe de id wordt gestroomd via synchrone en asynchrone aanroepen. Dit betekent dat .NET-toepassingen die HTTP-berichten ontvangen en verzenden, automatisch deelnemen aan gedistribueerde tracerings-id's, zonder speciale codering door de app-ontwikkelaar of bibliotheekafhankelijkheden van derden. Bibliotheken van derden kunnen ondersteuning toevoegen voor het verzenden van id's via niet-HTTP-berichtprotocollen of het ondersteunen van aangepaste coderingsconventies voor HTTP.
Spoorgegevens verzamelen
Geïnstrueerde code kan Activity objecten maken als onderdeel van een gedistribueerde trace, maar de informatie in deze objecten moet worden verzonden en geserialiseerd in een gecentraliseerd permanent archief, zodat de volledige tracering later nuttig kan worden beoordeeld. Er zijn verschillende telemetrieverzamelingsbibliotheken die deze taak kunnen uitvoeren, zoals Application Insights, OpenTelemetryof een bibliotheek die wordt geleverd door een externe telemetrie of APM-leverancier. Ontwikkelaars kunnen ook hun eigen aangepaste telemetrieverzameling voor activiteiten maken met behulp van System.Diagnostics.ActivityListener of System.Diagnostics.DiagnosticListener. ActivityListener biedt ondersteuning voor het observeren van elke activiteit, ongeacht of de ontwikkelaar daar vooraf kennis van heeft. Hierdoor is ActivityListener een eenvoudige en flexibele oplossing voor algemeen gebruik. Het gebruik van DiagnosticListener is daarentegen een complexer scenario waarbij de geïnstrumenteerde code actief gemaakt moet worden door het aanroepen van DiagnosticSource.StartActivity en de verzamelingsbibliotheek moet weten welke exacte naamgevingsinformatie de geïnstrumenteerde code heeft gebruikt bij het starten ervan. Met behulp van DiagnosticSource en DiagnosticListener kunnen de maker en listener willekeurige .NET-objecten uitwisselen en aangepaste conventies voor het doorgeven van gegevens tot stand brengen.
Monsterneming
Voor verbeterde prestaties in toepassingen met hoge doorvoer ondersteunt gedistribueerde tracering op .NET alleen steekproeven in een subset van traceringen in plaats van ze allemaal op te nemen. Voor activiteiten die zijn gemaakt met de aanbevolen ActivitySource.StartActivity-API, kunnen telemetrieverzamelingsbibliotheken steekproeven beheren met de ActivityListener.Sample callback. De logboekbibliotheek kan ervoor kiezen om de activiteit helemaal niet te maken, om deze te maken met de minimale informatie die nodig is om het verspreiden van tracerings-id's mogelijk te maken, of om deze te vullen met volledige diagnostische informatie. Deze keuzes maken een afweging tussen het verhogen van de prestatieoverhead voor het verhogen van het diagnostische hulpprogramma. Activiteiten die zijn gestart met het oudere patroon voor het aanroepen van Activity.Activity en DiagnosticSource.StartActivity kunnen ook ondersteuning bieden voor diagnosticListener-steekproeven door eerst DiagnosticSource.IsEnabledaan te roepen. Zelfs bij het vastleggen van volledige diagnostische gegevens is de .NET-implementatie ontworpen om snel te zijn, in combinatie met een efficiënte collector, kan een activiteit worden gemaakt, gevuld en verzonden in ongeveer een microseconde op moderne hardware. Steekproeven kunnen de instrumentatiekosten verlagen tot minder dan 100 nanoseconden voor elke activiteit die niet is vastgelegd.
Volgende stappen
Raadpleeg de Distributed Tracing Instrumentationvoor voorbeeldcode om te beginnen met gedistribueerde tracering in .NET-toepassingen.
Zie Ingebouwde activiteiten in .NETvoor een lijst met activiteiten die systeemeigen worden verzonden door .NET.