Conceitos de rastreamento distribuído do .NET

O rastreamento distribuído é uma técnica de diagnóstico que ajuda os engenheiros a localizar falhas e problemas de desempenho em aplicativos, especialmente aqueles que podem ser distribuídos em vários computadores ou processos. Confira a Visão Geral do Rastreamento Distribuído para obter informações gerais sobre a utilidade do rastreamento distribuído e o código de exemplo para começar.

Rastreamentos e atividades

Sempre que uma nova solicitação é recebida por um aplicativo, ela pode ser associada a um rastreamento. Nos componentes do aplicativo gravados no .NET, as unidades de trabalho em um rastreamento são representadas por instâncias de System.Diagnostics.Activity e o rastreamento como um todo forma uma árvore dessas Atividades, potencialmente abrangendo vários processos distintos. A primeira Atividade criada para uma nova solicitação forma a raiz da árvore de rastreamento e controla a duração geral e o êxito/falha ao lidar com a solicitação. As atividades filho podem ser criadas opcionalmente para subdividir o trabalho em diferentes etapas que podem ser rastreadas individualmente. Por exemplo, considerando uma Atividade que rastreia uma solicitação HTTP de entrada específica em um servidor Web, as atividades filho poderiam ser criadas para rastrear cada uma das consultas de banco de dados necessárias para concluir a solicitação. Isso permite que a duração e o êxito de cada consulta sejam registrados de forma independente. As atividades podem registrar outras informações para cada unidade de trabalho, como OperationName, pares nome-valor chamados Tags e Events. O nome identifica o tipo de trabalho que está sendo executado, as marcas podem registrar parâmetros descritivos do trabalho e os eventos são um mecanismo de registro em log simples para registrar mensagens de diagnóstico com carimbo de data/hora.

Observação

Outro nome comum do setor para unidades de trabalho em um rastreamento distribuído são 'Spans'. O .NET adotou o termo 'Atividade' há muitos anos, antes do nome 'Span' ser bem estabelecido para esse conceito.

IDs de atividade

As relações pai-filho entre Atividades na árvore de rastreamento distribuída são estabelecidas usando IDs exclusivas. A implementação do rastreamento distribuído pelo NET dá suporte a dois esquemas de ID: o TraceContext padrão do W3C, que é o padrão no .NET 5+, e uma convenção do .NET mais antiga chamada 'Hierárquica' disponível para compatibilidade com versões anteriores. Activity.DefaultIdFormat controla qual esquema de ID é usado. No padrão TraceContext do W3C, cada rastreamento recebe uma ID de rastreamento de 16 bytes globalmente exclusiva (Activity.TraceId) e cada Atividade no rastreamento recebe uma ID de intervalo exclusiva de 8 bytes (Activity.SpanId). Cada Atividade registra a ID de rastreamento, sua própria ID de intervalo e a ID de intervalo de seu pai (Activity.ParentSpanId). Como os rastreamentos distribuídos podem rastrear o trabalho entre os limites do processo, as Atividades pai e filho podem não estar no mesmo processo. A combinação de uma ID de rastreamento e id de intervalo pai pode identificar exclusivamente a Atividade pai globalmente, independentemente do processo em que reside.

Activity.DefaultIdFormat controla qual formato de ID é usado para iniciar novos rastreamentos, mas, por padrão, adicionar uma nova Atividade a um rastreamento existente usa qualquer formato que a Atividade pai esteja usando. A definição de Activity.ForceDefaultIdFormat como true substitui esse comportamento e cria todas as novas Atividades com DefaultIdFormat, mesmo quando o pai usa um formato de ID diferente.

Iniciar e parar Atividades

Cada thread em um processo pode ter um objeto de atividade correspondente que está rastreando o trabalho que ocorre nesse thread, acessível por meio de Activity.Current. A atividade atual flui automaticamente ao longo de todas as chamadas síncronas em um thread, bem como as seguintes chamadas assíncronas processadas em threads diferentes. Se a Atividade A for a atividade atual em um thread e o código iniciar uma nova Atividade B, B se tornará a nova atividade atual nesse thread. Por padrão, a atividade B também tratará a Atividade A como seu pai. Quando a Atividade B for interrompida posteriormente, a atividade A será restaurada como a Atividade atual no thread. Quando uma Atividade é iniciada, ela captura a hora atual como Activity.StartTimeUtc. Quando é interrompida, Activity.Duration é calculado como a diferença entre a hora atual e a hora de início.

Coordenar entre os limites do processo

Para rastrear o trabalho entre os limites do processo, as IDs pai da Atividade precisam ser transmitidas pela rede para que o processo de recebimento possa criar Atividades que façam referência a elas. Ao usar o formato de ID TraceContext do W3C, o .NET também usa os cabeçalhos HTTP recomendados pelo padrão para transmitir essas informações. Ao usar o formato de ID Hierarchical, o .NET usa um cabeçalho HTTP de id de solicitação personalizado para transmitir a ID. Ao contrário de muitos outros runtimes de linguagem, as bibliotecas internas do .NET, como o servidor Web ASP.NET e o System.Net.Http, entendem nativamente como decodificar e codificar IDs de atividade em mensagens HTTP. O runtime também entende como fluir a ID por chamadas síncronas e assíncronas. Isso significa que aplicativos .NET que recebem e emitem mensagens HTTP participam do fluxo de IDs de rastreamento distribuído automaticamente, sem codificação especial pelo desenvolvedor do aplicativo ou dependências de biblioteca de terceiros. As bibliotecas de terceiros podem adicionar suporte para transmitir IDs por protocolos de mensagem não HTTP ou dar suporte a convenções de codificação personalizadas para HTTP.

Coletar rastreamentos

O código instrumentado pode criar objetos Activity como parte de um rastreamento distribuído, mas as informações nesses objetos precisam ser transmitidas e serializadas em um armazenamento centralizado persistente para que todo o rastreamento possa ser examinado posteriormente de forma útil. Há várias bibliotecas de coleções de telemetria que podem fazer essa tarefa, como Application Insights, OpenTelemetry ou uma biblioteca fornecida por um fornecedor de telemetria ou APM de terceiros. Como alternativa, os desenvolvedores podem criar sua própria coleção de telemetria de Atividade personalizada usando System.Diagnostics.ActivityListener ou System.Diagnostics.DiagnosticListener. O ActivityListener dá suporte à observação de qualquer Atividade, independentemente de o desenvolvedor ter algum conhecimento prévio sobre ela. Isso torna o ActivityListener uma solução de uso geral simples e flexível. Por outro lado, o uso do DiagnosticListener é um cenário mais complexo que exige que o código instrumentado aceite invocando DiagnosticSource.StartActivity e a biblioteca de coleção deve ter conhecimento das informações exatas de nomenclatura que o código instrumentado usou ao iniciá-lo. O uso de DiagnosticSource e DiagnosticListener permite que o criador e o ouvinte troquem objetos arbitrários do .NET e estabeleçam convenções para passagem de informações personalizadas.

amostragem

Para melhorar o desempenho em aplicativos de alta taxa de transferência, o rastreamento distribuído no .NET dá suporte à amostragem apenas de um subconjunto de rastreamentos em vez de registrar todos eles. Para atividades criadas com a API ActivitySource.StartActivity recomendada, as bibliotecas de coleção de telemetria podem controlar a amostragem com o retorno de chamada ActivityListener.Sample. A biblioteca de registros em log pode optar por não criar a Atividade, criá-la com informações mínimas necessárias para propagar a distribuição de IDs de rastreamento ou para preenchê-la com informações de diagnóstico completas. Essas opções compensam o aumento da sobrecarga de desempenho para aumentar o utilitário de diagnóstico. As Atividades que são iniciadas usando o padrão mais antigo de invocação Activity.Activity e DiagnosticSource.StartActivity também podem dar suporte à amostragem DiagnosticListener chamando DiagnosticSource.IsEnabled primeiro. Ao capturar informações completas de diagnóstico, a implementação do .NET foi projetada para ser rápida, juntamente com um coletor eficiente, uma Atividade pode ser criada, populada e transmitida em um microssegundo no hardware moderno. A amostragem pode reduzir o custo de instrumentação para menos de 100 nanossegundos para cada Atividade não registrada.

Próximas etapas

Para obter um código de exemplo para começar a usar o rastreamento distribuído em aplicativos .NET, consulte a Instrumentação de Rastreamento Distribuído.