Rastreamento distribuído e correlação por meio de mensagens do Barramento de Serviço
Um dos problemas comuns no desenvolvimento de microsserviços é a capacidade de rastrear a operação de um cliente em todos os serviços que estão envolvidos no processamento. É útil para depuração, análise de desempenho, testes A/B e outros cenários típicos de diagnóstico. Uma parte desse problema é o rastreamento de partes lógicas do trabalho, que inclui o resultado do processamento de mensagens e a latência e as chamadas de dependência externa. Outra parte é correlação desses eventos de diagnóstico além dos limites do processo.
Quando um produtor envia uma mensagem por meio de uma fila, normalmente acontece no escopo de alguma outra operação lógica, iniciado por algum outro cliente ou serviço. A mesma operação dará continuidade ao consumidor quando ele recebe uma mensagem. O produtor e o consumidor (e outros serviços que processam a operação), presumivelmente emitem eventos de telemetria para rastrear o fluxo e o resultado da operação. Para correlacionar esses eventos e rastrear a operação end-to-end, cada serviço que informa a telemetria deve gravar todos os eventos com um contexto de rastreamento.
Mensagens do Barramento de Serviço do Microsoft Azure definiu propriedades de carga que produtores e consumidores devem usar para passar esse contexto de rastreamento. O protocolo é baseado no contexto de rastreamento W3C.
Nome da propriedade | Descrição |
---|---|
Diagnostic-Id |
Identificador exclusivo de uma chamada externa do produtor para a fila. Consulte cabeçalho pai de rastreamento de contexto de rastreamento do W3C para obter o formato |
Rastreamento automático do cliente .NET do Barramento de Serviço
A classe ServiceBusProcessor
do cliente do Barramento de Serviço de Mensagens do Azure para .NET fornece pontos de instrumentação de rastreamento que podem ser conectados por sistemas de rastreamento ou por parte do código de cliente. A instrumentação permite controlar todas as chamadas para o serviço de mensagens do Barramento de Serviço do lado do cliente. Se o processamento de mensagens for feito com o ProcessMessageAsync
do ServiceBusProcessor
(padrão do manipulador de mensagens), ele também será instrumentado.
Rastreando o Application Insights do Azure
O Microsoft Application Insights fornece recursos de monitoramento de desempenho avançado, incluindo solicitações automáticas e rastreamento de dependências.
Dependendo do tipo do seu projeto, instale o SDK do Application Insights:
- ASP.NET - instalar a versão 2.5-beta2 ou superior
- ASP.NET Core - instalar a versão 2.2.0-beta2 ou superior. Esses links fornecem detalhes sobre como instalar o SDK, criando recursos e configurando o SDK (se necessário). Para aplicativos diferentes do ASP.NET, consulte o artigo Application Insights do Azure para aplicativos de Console.
Se você usar o ProcessMessageAsync
do ServiceBusProcessor
(padrão do manipulador de mensagens) para processar mensagens, o processamento de mensagens também será instrumentado. Todas as chamadas do Barramento de Serviço feitas pelo seu serviço são automaticamente rastreadas e correlacionadas com outros itens de telemetria. Caso contrário, consulte o exemplo a seguir para o controle de processamento de mensagem manual.
Processamento de mensagem de rastreamento
async Task ProcessAsync(ProcessMessageEventArgs args)
{
ServiceBusReceivedMessage message = args.Message;
if (message.ApplicationProperties.TryGetValue("Diagnostic-Id", out var objectId) && objectId is string diagnosticId)
{
var activity = new Activity("ServiceBusProcessor.ProcessMessage");
activity.SetParentId(diagnosticId);
// If you're using Microsoft.ApplicationInsights package version 2.6-beta or higher, you should call StartOperation<RequestTelemetry>(activity) instead
using (var operation = telemetryClient.StartOperation<RequestTelemetry>("Process", activity.RootId, activity.ParentId))
{
telemetryClient.TrackTrace("Received message");
try
{
// process message
}
catch (Exception ex)
{
telemetryClient.TrackException(ex);
operation.Telemetry.Success = false;
throw;
}
telemetryClient.TrackTrace("Done");
}
}
}
Neste exemplo, é relatada a telemetria da solicitação de cada mensagem processada, com um carimbo de data/hora, a duração e o resultado (êxito). A telemetria também tem um conjunto de propriedades de correlação. Rastreamentos aninhados e exceções relatadas durante o processamento da mensagem também são marcadas com propriedades de correlação que os representam como filhos do RequestTelemetry
.
Caso faça chamadas para componentes externos com suporte durante o processamento da mensagem, elas também serão automaticamente rastreadas e correlacionadas. Consulte Acompanhar operações personalizadas com o SDK do .NET do Application Insights para rastreamento manual e correlação.
Se você estiver executando qualquer código externo além do SDK do Application Insights, espere para ver uma duração mais longa ao exibir os logs de Application Insights.
Isso não significa que houve um atraso no recebimento da mensagem. Nesse cenário, a mensagem já foi recebida, pois a ela é passada como um parâmetro para o código do SDK. E a marca name nos logs do App Insights (Processo) indica que agora a mensagem está sendo processada pelo código de processamento de evento externo. Esse problema não é relacionado ao Azure. Em vez disso, essas métricas referem-se à eficiência do seu código externo, dado que a mensagem já foi recebida do Barramento de Serviço.
Acompanhamento com OpenTelemetry
A biblioteca de clientes .NET de Barramento de Serviço versão 7.5.0 e posterior dá suporte a OpenTelemetry no modo experimental. Para obter mais informações, confira Rastreamento distribuído no SDK do .NET.
Controle sem o sistema de rastreamento
Caso seu sistema de rastreamento não dê suporte ao rastreamento automático de chamadas do Barramento de Serviço, você pode estar procurando adicionar esse suporte a um sistema de rastreamento ou ao seu aplicativo. Esta seção descreve eventos de diagnóstico enviados pelo cliente .NET do Barramento de Serviço.
Cliente de .NET do Barramento de Serviço é instrumentado usando primitivos de rastreamento .NET System.Diagnostics.Activity e System.Diagnostics.DiagnosticSource.
Activity
serve como um contexto de rastreamento enquanto DiagnosticSource
é um mecanismo de notificação.
Se não houver nenhum ouvinte para os eventos do DiagnosticSource, a instrumentação será desativada, mantendo o custo zero da instrumentação. O DiagnosticSource fornece todo o controle para o ouvinte:
- o ouvinte controla quais fontes e eventos escutar
- o ouvinte controla a amostragem e taxa do evento
- os eventos são enviados com uma carga que fornece o contexto completo para que você possa acessar e modificar o objeto de mensagem durante o evento
Familiarize-se com Guia do Usuário DiagnosticSource antes de continuar com a implementação.
Vamos criar um ouvinte de eventos do Barramento de Serviço no aplicativo do ASP.NET Core que grava logs com o Microsoft.Extension.Logger. Ele usa a biblioteca System.Reactive.Core para assinar DiagnosticSource (também é fácil assinar DiagnosticSource sem ela)
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory factory, IApplicationLifetime applicationLifetime)
{
// configuration...
var serviceBusLogger = factory.CreateLogger("Azure.Messaging.ServiceBus");
IDisposable innerSubscription = null;
IDisposable outerSubscription = DiagnosticListener.AllListeners.Subscribe(delegate (DiagnosticListener listener)
{
// subscribe to the Service Bus DiagnosticSource
if (listener.Name == "Azure.Messaging.ServiceBus")
{
// receive event from Service Bus DiagnosticSource
innerSubscription = listener.Subscribe(delegate (KeyValuePair<string, object> evnt)
{
// Log operation details once it's done
if (evnt.Key.EndsWith("Stop"))
{
Activity currentActivity = Activity.Current;
serviceBusLogger.LogInformation($"Operation {currentActivity.OperationName} is finished, Duration={currentActivity.Duration}, Id={currentActivity.Id}, StartTime={currentActivity.StartTimeUtc}");
}
});
}
});
applicationLifetime.ApplicationStopping.Register(() =>
{
outerSubscription?.Dispose();
innerSubscription?.Dispose();
});
}
Neste exemplo, o ouvinte registra duração, resultado, identificador exclusivo e a hora de início para cada operação de Barramento de Serviço.
Eventos
Todos os eventos terão as seguintes propriedades que estão em conformidade com a especificação de telemetria aberta: https://github.com/open-telemetry/opentelemetry-specification/blob/master/specification/trace/api.md.
message_bus.destination
– fila/tópico/caminho de assinaturapeer.address
– namespace totalmente qualificadokind
– produtor, consumidor ou cliente. O produtor é usado ao enviar mensagens, o consumidor é usado para recebê-las e o cliente é usado para resolvê-las.component
–servicebus
Todos os eventos também têm Entity
e propriedades Endpoint
.
Entity
- - Nome da entidade (fila, tópico etc.)Endpoint
- URL do endpoint do Barramento de Serviço
Operações instrumentadas
Veja abaixo a lista completa de operações instrumentadas:
Nome de operação | API controlada |
---|---|
ServiceBusSender.Send | ServiceBusSender.SendMessageAsync ServiceBusSender.SendMessagesAsync |
ServiceBusSender.Schedule | ServiceBusSender.ScheduleMessageAsync ServiceBusSender.ScheduleMessagesAsync |
ServiceBusSender.Cancel | ServiceBusSender.CancelScheduledMessageAsync ServiceBusSender.CancelScheduledMessagesAsync |
ServiceBusReceiver.Receive | ServiceBusReceiver.ReceiveMessageAsync ServiceBusReceiver.ReceiveMessagesAsync |
ServiceBusReceiver.ReceiveDeferred | ServiceBusReceiver.ReceiveDeferredMessagesAsync |
ServiceBusReceiver.Peek | ServiceBusReceiver.PeekMessageAsync ServiceBusReceiver.PeekMessagesAsync |
ServiceBusReceiver.Abandon | ServiceBusReceiver.AbandonMessagesAsync |
ServiceBusReceiver.Complete | ServiceBusReceiver.CompleteMessagesAsync |
ServiceBusReceiver.DeadLetter | ServiceBusReceiver.DeadLetterMessagesAsync |
ServiceBusReceiver.Defer | ServiceBusReceiver.DeferMessagesAsync |
ServiceBusReceiver.RenewMessageLock | ServiceBusReceiver.RenewMessageLockAsync |
ServiceBusSessionReceiver.RenewSessionLock | ServiceBusSessionReceiver.RenewSessionLockAsync |
ServiceBusSessionReceiver.GetSessionState | ServiceBusSessionReceiver.GetSessionStateAsync |
ServiceBusSessionReceiver.SetSessionState | ServiceBusSessionReceiver.SetSessionStateAsync |
ServiceBusProcessor.ProcessMessage | Retorno de chamada do processador definido em ServiceBusProcessor. Propriedade ProcessMessageAsync |
ServiceBusSessionProcessor.ProcessSessionMessage | Retorno de chamada do processador definido em ServiceBusSessionProcessor. Propriedade ProcessMessageAsync |
Filtragem e amostragem
Em alguns casos, é desejável para fazer logon apenas uma parte dos eventos para reduzir o consumo de armazenamento ou sobrecarga de desempenho. Você pode fazer somente eventos de 'Stop' (como no exemplo anterior) ou a porcentagem de exemplo dos eventos.
DiagnosticSource
fornecem a maneira de conseguir isso com IsEnabled
predicado. Para obter mais informações, consulte Filtragem com base em contexto em DiagnosticSource.
IsEnabled
pode ser chamado várias vezes para uma única operação para minimizar o impacto no desempenho.
IsEnabled
é chamado na sequência a seguir:
IsEnabled(<OperationName>, string entity, null)
por exemplo,IsEnabled("ServiceBusSender.Send", "MyQueue1")
. Observe que não há nenhum 'Start' ou 'Stop' no final. Usá-lo para filtrar as operações específicas ou filas. Se o método de retorno de chamada retornarfalse
, os eventos da operação não serão enviados.- Para as operações de 'Processo' e 'ProcessSession', você também receberá
IsEnabled(<OperationName>, string entity, Activity activity)
retorno de chamada. Use-o para filtrar eventos com base emactivity.Id
ou propriedades de marcas.
- Para as operações de 'Processo' e 'ProcessSession', você também receberá
IsEnabled(<OperationName>.Start)
por exemplo,IsEnabled("ServiceBusSender.Send.Start")
. Verifica se o evento 'Start' deva ser acionado. O resultado afeta apenas o evento 'Start', mas instrumentações adicionais não dependem disso.
Não há nenhum IsEnabled
para o evento 'Stop'.
Se algum resultado da operação for a exceção, IsEnabled("ServiceBusSender.Send.Exception")
é chamado. Você só pode assinar eventos de 'Exceções' e impedir o restante da instrumentação. Nesse caso, você ainda precisa tratar essas exceções. Como outras instrumentações estão desabilitadas, você não deve esperar que o contexto de rastreamento exiba as mensagens do consumidor para o produtor.
Você pode usar IsEnabled
também implementar estratégias de amostragem. Amostragem com base no Activity.Id
ou no Activity.RootId
garante uma amostragem consistente em todas as camadas (desde que ela seja propagada pelo sistema de rastreamento ou pelo seu código).
Na presença de vários ouvintes DiagnosticSource
para a mesma fonte, apenas um ouvinte precisa aceitar o evento, portanto não há garantia que o IsEnabled
será chamado.
Conteúdo relacionado
- Uma biblioteca que pode ajudar os desenvolvedores a ter a telemetria emitida por padrão é NServiceBus.
- Correlação de Application Insights
- Acompanhar operações personalizadas com o SDK do .NET do Application Insights