Rastreio distribuído e correlação através das mensagens do Service Bus
Um dos problemas comuns no desenvolvimento de micro serviços é a capacidade de rastrear a operação de um cliente através de 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 peças lógicas de trabalho. Inclui resultados e latência de processamento de mensagens e chamadas de dependência externa. Outra parte é a correlação desses eventos de diagnóstico além dos limites do processo.
Quando um produtor envia uma mensagem através de uma fila, isso normalmente acontece no escopo de alguma outra operação lógica, iniciada por algum outro cliente ou serviço. A mesma operação é continuada pelo consumidor assim que recebe uma mensagem. Tanto o produtor quanto 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 de ponta a ponta, cada serviço que relata a telemetria tem que carimbar cada evento com um contexto de rastreamento. Uma biblioteca que pode ajudar os desenvolvedores a ter toda essa telemetria emitida por padrão é o NServiceBus.
O sistema de mensagens do Barramento de Serviço do Microsoft Azure definiu propriedades de carga útil que os produtores e consumidores devem usar para passar esse contexto de rastreamento. O protocolo é baseado no W3C Trace-Context.
Nome de Propriedade | Description |
---|---|
ID de diagnóstico | Identificador exclusivo de uma chamada externa do produtor para a fila. Consulte o cabeçalho traceparent Trace-Context do W3C para obter o formato |
Rastreamento automático do cliente .NET do Service Bus
A ServiceBusProcessor
classe 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 parte do código do cliente. A instrumentação permite rastrear todas as chamadas para o serviço de mensagens do Service Bus do lado do cliente. Se o processamento de mensagens for feito usando ProcessMessageAsync
de (padrão do manipulador de mensagens), o processamento de ServiceBusProcessor
mensagens também será instrumentado.
Acompanhamento com o Azure Application Insights
O Microsoft Application Insights fornece recursos avançados de monitoramento de desempenho, incluindo solicitação automágica e rastreamento de dependência.
Dependendo do tipo de projeto, instale o SDK do Application Insights:
- ASP.NET - instale a versão 2.5-beta2 ou superior
- ASP.NET Core - instale a versão 2.2.0-beta2 ou superior. Esses links fornecem detalhes sobre como instalar o SDK, criar recursos e configurar o SDK (se necessário). Para non-ASP.NET aplicativos, consulte o artigo Azure Application Insights for Console Applications .
Se você usar ProcessMessageAsync
de (padrão do manipulador de mensagens) para processar mensagens, o processamento de ServiceBusProcessor
mensagens também será instrumentado. Todas as chamadas do Service Bus 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 rastreamento manual de processamento de mensagens.
Processamento de mensagens 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, a telemetria de solicitação é relatada para cada mensagem processada, tendo um carimbo de data/hora, duração e resultado (êxito). A telemetria também tem um conjunto de propriedades de correlação. Rastreamentos aninhados e exceções relatados durante o processamento de mensagens também são marcados com propriedades de correlação que os representam como 'filhos' do RequestTelemetry
.
Caso você faça chamadas para componentes externos suportados durante o processamento de mensagens, eles também são automaticamente rastreados e correlacionados. Consulte Rastrear 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 ver uma duração maior ao exibir os logs do Application Insights.
Isso não significa que houve um atraso no recebimento da mensagem. Nesse cenário, a mensagem já foi recebida desde que a mensagem é passada como um parâmetro para o código SDK. Além disso, a tag de nome nos logs do App Insights (Processo) indica que a mensagem está sendo processada pelo código de processamento de eventos externos. Esse problema não está relacionado ao Azure. Em vez disso, essas métricas se referem à eficiência do seu código externo, dado que a mensagem já foi recebida do Service Bus.
Rastreamento com OpenTelemetry
A biblioteca de cliente .NET do Service Bus versão 7.5.0 e posterior oferece suporte a OpenTelemetry no modo experimental. Para obter mais informações, consulte Rastreamento distribuído no .NET SDK.
Rastreamento sem sistema de rastreamento
Caso seu sistema de rastreamento não ofereça suporte ao rastreamento automático de chamadas do Service Bus, você pode estar pensando em 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 Service Bus.
O Service Bus .NET Client é 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 um ouvinte para os eventos DiagnosticSource, a instrumentação estará desativada, mantendo zero custos de instrumentação. DiagnosticSource dá todo o controle ao ouvinte:
- O ouvinte controla quais fontes e eventos ouvir
- O ouvinte controla a taxa de eventos e a amostragem
- os eventos são enviados com uma carga que fornece contexto completo para que você possa acessar e modificar o objeto Message durante o evento
Familiarize-se com o Guia do Usuário do DiagnosticSource antes de prosseguir com a implementação.
Vamos criar um ouvinte para eventos do Service Bus no aplicativo ASP.NET Core que grava logs com Microsoft.Extension.Logger. Ele usa a biblioteca System.Reative.Core para assinar o DiagnosticSource (também é fácil assinar o DiagnosticSource sem ele)
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 a duração, o resultado, o identificador exclusivo e a hora de início de cada operação do Service Bus.
evento
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
– caminho da fila/tópico/subscriçãopeer.address
– namespace totalmente qualificadokind
– produtor, consumidor ou cliente. O produtor é usado ao enviar mensagens, o consumidor ao receber e o cliente ao se acomodar.component
–servicebus
Todos os eventos também têm Entity
e Endpoint
propriedades.
Entity
- - Nome da entidade (fila, tópico e assim por diante.)Endpoint
- URL do ponto de extremidade do Service Bus
Operações instrumentadas
Aqui está a lista completa de operações instrumentadas:
Nome da Operação | API rastreada |
---|---|
ServiceBusSender.Send | ServiceBusSender.SendMessageAsync ServiceBusSender.SendMessagesAsync |
ServiceBusSender.Schedule | ServiceBusSender.ScheduleMessageAsync ServiceBusSender.ScheduleMessagesAsync |
ServiceBusSender.Cancelar | ServiceBusSender.CancelScheduledMessageAsync ServiceBusSender.CancelScheduledMessagesAsync |
ServiceBusReceiver.Receber | 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 no ServiceBusProcessor. Propriedade ProcessMessageAsync |
ServiceBusSessionProcessor.ProcessSessionMessage | Retorno de chamada do processador definido em ServiceBusSessionProcessor. Propriedade ProcessMessageAsync |
Filtragem e amostragem
Em alguns casos, é desejável registrar apenas parte dos eventos para reduzir a sobrecarga de desempenho ou o consumo de armazenamento. Você pode registrar apenas eventos 'Stop' (como no exemplo anterior) ou porcentagem de amostra dos eventos.
DiagnosticSource
fornecer maneira de alcançá-lo com IsEnabled
predicado. Para obter mais informações, consulte Filtragem baseada 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 seguinte sequência:
IsEnabled(<OperationName>, string entity, null)
por exemplo,IsEnabled("ServiceBusSender.Send", "MyQueue1")
. Observe que não há 'Iniciar' ou 'Parar' no final. Use-o para filtrar operações ou filas específicas. Se o método de retorno de chamada retornarfalse
, os eventos para a operação não serão enviados.- Para as operações 'Process' e 'ProcessSession', você também recebe
IsEnabled(<OperationName>, string entity, Activity activity)
retorno de chamada. Use-o para filtrar eventos com base nasactivity.Id
propriedades ou Tags.
- Para as operações 'Process' e 'ProcessSession', você também recebe
IsEnabled(<OperationName>.Start)
por exemplo,IsEnabled("ServiceBusSender.Send.Start")
. Verifica se o evento 'Start' deve ser acionado. O resultado afeta apenas o evento 'Start', mas a instrumentação adicional não depende dele.
Não há IsEnabled
para o evento 'Stop'.
Se algum resultado da operação for exceção, IsEnabled("ServiceBusSender.Send.Exception")
será chamado. Só pode subscrever eventos de "Exceção" e impedir o resto da instrumentação. Neste caso, você ainda tem que lidar com essas exceções. Como outra instrumentação está desativada, você não deve esperar que o contexto de rastreamento flua com as mensagens do consumidor para o produtor.
Você também pode usar IsEnabled
implementar estratégias de amostragem. A amostragem com base no ou Activity.RootId
garante uma Activity.Id
amostragem consistente em todos os pneus (desde que seja propagada pelo sistema de rastreamento ou pelo seu próprio código).
Na presença de vários DiagnosticSource
ouvintes para a mesma fonte, basta que apenas um ouvinte aceite o evento, portanto, não há garantia de que IsEnabled
seja chamado.
Próximos passos
- Correlação do Application Insights
- O Application Insights monitora as dependências para ver se REST, SQL ou outros recursos externos estão deixando você lento.
- Acompanhe operações personalizadas com o SDK do .NET do Application Insights