Seguimiento y correlación distribuidos del servicio de mensajería de Service Bus
Uno de los problemas comunes en el desarrollo de microservicios es la capacidad de realizar un seguimiento de las operaciones de un cliente a través de todos los servicios que intervienen en el proceso. Es útil para la realizar depuraciones, análisis de rendimiento, pruebas A/B y otros escenarios de diagnóstico típicos. Una parte de este problema es el seguimiento de partes lógicas del trabajo, que incluye el resultado del procesamiento de mensajes y la latencia y las llamadas de dependencia externas. Otra parte del problema es la correlación de estos eventos de diagnóstico más allá de los límites del proceso.
Cuando un productor envía un mensaje a través de una cola, normalmente se produce en el ámbito de cualquier otra operación lógica que inició algún otro cliente o servicio. Igualmente, el consumidor continúa con la misma operación después de recibir un mensaje. Tanto el productor como el consumidor (y otros servicios que procesan la operación) emiten eventos de telemetría para hacer un seguimiento del flujo de la operación y su resultado. Para poder correlacionar estos eventos y realizar un seguimiento de la operación de un extremo a otro, cada servicio que notifica la telemetría debe marcar todos los eventos con un contexto de seguimiento.
El servicio de mensajería de Microsoft Azure Service Bus ha definido las propiedades de carga que deben usar los productores y consumidores para poder pasar estos contextos de seguimiento. El protocolo se basa en el contexto de seguimiento de W3C.
Nombre de la propiedad | Descripción |
---|---|
Diagnostic-Id |
Identificador único de una llamada externa del productor a la cola. Consulte Encabezado primario de seguimiento de contexto de W3C para el formato |
Seguimiento automático del cliente .NET de Service Bus
La clase ServiceBusProcessor
del cliente de Azure Messaging Service Bus para .NET proporciona varios puntos de instrumentación de seguimiento que se pueden enlazar mediante los sistemas de seguimiento o los fragmentos de código de cliente. La instrumentación permite realizar un seguimiento de todas las llamadas al servicio de mensajería de Service Bus desde el lado del cliente. Si el procesamiento de mensajes se realiza con ProcessMessageAsync
de ServiceBusProcessor
(patrón del controlador de mensajes), el procesamiento de mensajes también se instrumentará.
Realizar un seguimiento con Azure Application Insights
Microsoft Application Insights proporciona funcionalidades de supervisión de alto rendimiento entre las que se incluyen las solicitudes automágicas o el seguimiento de dependencias.
Dependiendo del tipo de proyecto, instale el SDK de Application Insights:
- ASP.NET: instale la versión 2.5-beta2 o superior.
- ASP.NET Core: instale la versión 2.2.0-beta2 o superior. Estos vínculos proporcionan detalles sobre la instalación del SDK, la creación de recursos y la configuración del SDK (si fuera necesario). Para aplicaciones que no sean de ASP.NET, consulte el artículo Azure Application Insights for Console Applications (Azure Application Insights para las aplicaciones de consola).
Si usa ProcessMessageAsync
de ServiceBusProcessor
(patrón del controlador de mensajes) para procesar los mensajes, el procesamiento de mensajes también se instrumentará. Se realizará el seguimiento automático de todas las llamadas de Service Bus que se hayan hecho mediante el servicio y se correlacionarán con otros elementos de telemetría. En caso contrario, consulte el siguiente ejemplo para saber cómo realizar el seguimiento manual del procesamiento de mensajes.
Seguimiento del procesamiento de mensajes
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");
}
}
}
En este ejemplo, la telemetría de solicitudes se notifica en cada mensaje procesado e indica la marca de tiempo, la duración y el resultado (correcto). La telemetría también tiene un conjunto de propiedades de correlación. Igualmente, los seguimientos anidados y las excepciones que se notifican durante el procesamiento de mensajes también se marcan con propiedades de correlación que se representan como "elementos secundarios" de RequestTelemetry
.
Si realiza llamadas a componentes externos compatibles durante el procesamiento de mensajes, también se seguirán y correlacionarán de manera automática. Consulte Seguimiento de las operaciones personalizadas con el SDK de .NET para Application Insights, si quiere obtener más información sobre el seguimiento y la correlación manuales.
Si ejecuta código externo además del SDK de Application Insights, tenga previsto que la duración será mayor al ver registros de Application Insights.
Esto no significa que haya un retraso en la recepción del mensaje. En este escenario, el mensaje ya se ha recibido porque se ha pasado como un parámetro al código del SDK. Además, la etiqueta name de los registros de App Insights (Process) indica que el código de procesamiento de eventos externos está procesando el mensaje. Este problema no está relacionado con Azure. estas métricas ponen de manifiesto más bien la eficacia del código externo, dado que el mensaje ya se ha recibido de Service Bus.
Seguimiento con OpenTelemetry
La versión 7.5.0 y posteriores de la biblioteca cliente .NET de Service Bus admite OpenTelemetry en modo experimental. Para obtener más información, consulte Seguimiento distribuido en el SDK de .NET.
Realizar seguimientos sin sistema de seguimiento
Si el sistema de seguimiento no admite el seguimiento automático de llamadas de Service Bus, puede examinar la posibilidad de agregar dicha compatibilidad a un sistema de seguimiento o a su aplicación. En esta sección se describen los eventos de diagnóstico que envió el cliente .NET de Service Bus.
El cliente .NET de Service Bus se instrumentó mediante las primitivas de seguimiento de .NET System.Diagnostics.Activity y System.Diagnostics.DiagnosticSource.
Activity
actúa como un contexto de seguimiento mientras que DiagnosticSource
es un mecanismo de notificación.
Si no hay ningún agente de escucha para los eventos DiagnosticSource, la instrumentación estará desactivada y el costo de instrumentación será cero. DiagnosticSource proporciona todo el control al agente de escucha:
- El agente de escucha se encarga de controlar qué orígenes y eventos hay que escuchar.
- El agente de escucha controla el muestreo y la velocidad de los eventos.
- Los eventos se envían con una carga que proporciona un contexto completo para que pueda obtener acceso y modificar el objeto de mensaje durante el evento.
Familiarícese con DiagnosticSource User Guide (Guía de usuario de DiagnosticSource) antes de continuar con la implementación.
Vamos a crear un agente de escucha de eventos de Service Bus en la aplicación de ASP.NET Core que escriba registros con Microsoft.Extension.Logger. Este usa la biblioteca System.Reactive.Core para suscribirse a DiagnosticSource (aunque también es fácil suscribirse a DiagnosticSource sin este elemento).
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();
});
}
En este ejemplo, el agente de escucha registra la duración, el resultado, el identificador único y la hora de inicio de cada operación de Service Bus.
Eventos
Todos los eventos tendrán las propiedades siguientes que se ajustan a la especificación de telemetría abierta: https://github.com/open-telemetry/opentelemetry-specification/blob/master/specification/trace/api.md.
message_bus.destination
: ruta de acceso a la cola, el tema o la suscripción.peer.address
: espacio de nombres completo.kind
: productor, consumidor o cliente. El productor se usa al enviar mensajes, el consumidor al recibirlos y el cliente al liquidarlos.component
–servicebus
Todos los eventos tienen también las propiedades Entity
y Endpoint
.
Entity
: nombre de la entidad (cola, tema, etc.).Endpoint
: dirección URL del punto de conexión de Service Bus
Operaciones instrumentadas
Esta es la lista completa de operaciones instrumentadas:
Nombre de la operación | API de seguimiento |
---|---|
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 | Devolución de llamada del procesador establecida en ServiceBusProcessor. Propiedad ProcessMessageAsync |
ServiceBusSessionProcessor.ProcessSessionMessage | Devolución de llamada del procesador establecida en ServiceBusSessionProcessor. Propiedad ProcessMessageAsync |
Filtrado y muestreo
En algunos casos, es recomendable registrar parte de los eventos para reducir el consumo del almacenamiento o la sobrecarga del rendimiento. Para ello, puede registrar solo los eventos "Stop" (tal como se muestra en el ejemplo anterior) o un porcentaje del muestreo de los eventos.
DiagnosticSource
proporciona la forma de lograrlo mediante el predicado IsEnabled
. Para obtener más información, consulte Context-Based Filtering in DiagnosticSource (Filtrado basado en contexto en DiagnosticSource).
IsEnabled
puede recibir varias llamadas de una sola operación para así minimizar el impacto en el rendimiento.
IsEnabled
se llama en la siguiente secuencia:
IsEnabled(<OperationName>, string entity, null)
por ejemplo,IsEnabled("ServiceBusSender.Send", "MyQueue1")
. Tenga en cuenta que no hay ningún evento "Start" o "Stop" al final. Use esta opción para filtrar operaciones o colas determinadas. Si el método de devolución de llamada devuelvefalse
, no se envían los eventos de la operación.- También recibirá una devolución de llamada
IsEnabled(<OperationName>, string entity, Activity activity)
para las operaciones "Process" y "ProcessSession". Úsela para filtrar eventos basados enactivity.Id
o en propiedades de etiquetas.
- También recibirá una devolución de llamada
IsEnabled(<OperationName>.Start)
por ejemplo,IsEnabled("ServiceBusSender.Send.Start")
. Comprueba si se deben activar eventos "Start". El resultado solo afecta a los eventos "Start", pero la instrumentación adicional no depende de él.
No hay ningún elemento IsEnabled
para el evento "Stop".
Si algún resultado de la operación es una excepción, se llama a IsEnabled("ServiceBusSender.Send.Exception")
. Solo puede suscribirse a eventos "Exception" y evitar el resto de la instrumentación. En este caso, tendrá que administrar dichas excepciones. Como el resto de la instrumentación está deshabilitada, no espere que el contexto del seguimiento fluya con los mensajes de consumidor a productor.
Puede usar IsEnabled
y también implementar estrategias de muestreo. Gracias al muestreo basado en Activity.Id
o Activity.RootId
, puede obtener resultados de muestreo coherentes en todos los elementos (siempre y cuando se propague mediante el seguimiento del sistema o nuestro propio código).
Cuando hay varios clientes de escucha DiagnosticSource
en el mismo origen, un solo cliente de escucha no es suficiente para aceptar el evento, por lo que no se puede garantizar que llame a IsEnabled
.
Contenido relacionado
- Una biblioteca que puede ayudar a los desarrolladores a emitir todos estos datos de telemetría de manera predeterminada es NServiceBus.
- Correlación de Application Insights
- Realizar el seguimiento de operaciones personalizadas con el SDK de .NET para Application Insights