Distribuerad spårning och korrelation via Service Bus meddelanden

Ett av de vanliga problemen med utveckling av mikrotjänster är möjligheten att spåra åtgärder från en klient via alla tjänster som ingår i bearbetningen. Det är användbart för felsökning, prestandaanalys, A/B-testning och andra vanliga diagnostikscenarier. En del av det här problemet är att spåra logiska arbetsstycken. Den innehåller resultat för meddelandebearbetning och svarstid och externa beroendeanrop. En annan del är korrelation av dessa diagnostikhändelser utanför processgränserna.

När en producent skickar ett meddelande via en kö sker det vanligtvis i omfånget för någon annan logisk åtgärd som initieras av någon annan klient eller tjänst. Samma åtgärd fortsätter av konsumenten när den får ett meddelande. Både producent och konsument (och andra tjänster som bearbetar åtgärden) genererar förmodligen telemetrihändelser för att spåra åtgärdsflödet och resultatet. För att korrelera sådana händelser och spårningsåtgärder från slutpunkt till slutpunkt måste varje tjänst som rapporterar telemetri stämpla varje händelse med en spårningskontext.

Microsoft Azure Service Bus meddelandetjänster har definierade nyttolastegenskaper som producenter och konsumenter bör använda för att skicka sådana spårningskontexter. Protokollet baseras på W3C Trace-Context.

Egenskapens namn Description
Diagnostic-Id Unik identifierare för ett externt anrop från producent till kön. Se W3C Trace-Context traceparent-rubrik för formatet

Service Bus .NET-klient automatiskt

Klassen ServiceBusProcessorför Azure Messaging Service Bus-klienten för .NET tillhandahåller spårningsinstrumentationspunkter som kan kopplas av spårningssystem eller klientkod. Instrumentationen tillåter spårning av alla anrop till Service Bus meddelandetjänsten från klientsidan. Om meddelandebearbetningen görs med hjälp ProcessMessageAsync av ServiceBusProcessor (meddelandehanterarmönster) instrumenteras även meddelandebearbetningen.

Spårning med Azure Application Insights

Microsoft Application Insights tillhandahåller omfattande funktioner för prestandaövervakning, inklusive automatisk begärande- och beroendespårning.

Beroende på projekttyp installerar du Application Insights SDK:

  • ASP.NET – installera version 2.5-beta2 eller senare
  • ASP.NET Core – installera version 2.2.0-beta2 eller senare. De här länkarna innehåller information om hur du installerar SDK, skapar resurser och konfigurerar SDK (om det behövs). För program som inte ASP.NET finns i artikeln Azure Application Insights för konsolprogram.

Om du använderProcessMessageAsyncServiceBusProcessor(meddelandehanterarmönster) för att bearbeta meddelanden, instrumenteras även meddelandebearbetningen. Alla Service Bus-anrop som utförs av tjänsten spåras automatiskt och korreleras med andra telemetriobjekt. I annat fall kan du läsa följande exempel för manuell spårning av meddelandebearbetning.

Bearbetning av spårningsmeddelanden

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");
        }
    }
}

I det här exemplet rapporteras telemetri för begäran för varje bearbetat meddelande med tidsstämpel, varaktighet och resultat (lyckades). Telemetrin har också en uppsättning korrelationsegenskaper. Kapslade spårningar och undantag som rapporteras under meddelandebearbetningen stämplas också med korrelationsegenskaper som representerar dem som "underordnade" för RequestTelemetry.

Om du gör anrop till externa komponenter som stöds under meddelandebearbetningen spåras de också automatiskt och korreleras. Se Spåra anpassade åtgärder med Application Insights .NET SDK för manuell spårning och korrelation.

Om du kör någon extern kod utöver application Insights SDK förväntar du dig att se längre varaktighet när du visar Program Insights loggar.

Longer duration in Application Insights log

Det betyder inte att det var en fördröjning i mottagandet av meddelandet. I det här scenariot har meddelandet redan tagits emot eftersom meddelandet skickas som en parameter till SDK-koden. Och namntaggen i appen Insights loggar (process) anger att meddelandet nu bearbetas av din externa händelsebearbetningskod. Det här problemet är inte Azure-relaterat. I stället refererar dessa mått till effektiviteten i din externa kod eftersom meddelandet redan har tagits emot från Service Bus.

Spårning med OpenTelemetry

Service Bus .NET-klientbibliotek version 7.5.0 och senare stöder OpenTelemetry i experimentellt läge. Mer information finns i dokumentationen om distribuerad spårning i .NET SDK .

Spårning utan spårningssystem

Om spårningssystemet inte stöder automatisk Service Bus samtalsspårning kanske du funderar på att lägga till sådant stöd i ett spårningssystem eller i ditt program. I det här avsnittet beskrivs diagnostikhändelser som skickas av Service Bus .NET-klient.

Service Bus .NET-klienten är instrumenterad med hjälp av .NET-spårningsprimiterna System.Diagnostics.Activity och System.Diagnostics.DiagnosticSource.

Activity fungerar som en spårningskontext medan DiagnosticSource det är en meddelandemekanism.

Om det inte finns någon lyssnare för DiagnosticSource-händelserna är instrumentationen inaktiverad och behåller inga instrumenteringskostnader. DiagnosticSource ger lyssnaren all kontroll:

  • lyssnaren styr vilka källor och händelser som ska lyssnas på
  • lyssnaren kontrollerar händelsefrekvens och sampling
  • händelser skickas med en nyttolast som ger fullständig kontext så att du kan komma åt och ändra meddelandeobjektet under händelsen

Bekanta dig med DiagnosticSource-användarhandboken innan du fortsätter med implementeringen.

Nu ska vi skapa en lyssnare för Service Bus händelser i ASP.NET Core app som skriver loggar med Microsoft.Extension.Logger. Det använder System.Reactive.Core-biblioteket för att prenumerera på DiagnosticSource (det är också enkelt att prenumerera på DiagnosticSource utan det)

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();
    });
}

I det här exemplet loggar lyssnaren varaktighet, resultat, unik identifierare och starttid för varje Service Bus åtgärd.

Händelser

Alla händelser har följande egenskaper som överensstämmer med den öppna telemetrispecifikationen: https://github.com/open-telemetry/opentelemetry-specification/blob/master/specification/trace/api.md.

  • message_bus.destination – kö/ämne/prenumerationssökväg
  • peer.address – fullständigt kvalificerat namnområde
  • kind – antingen producent, konsument eller klient. Producent används när meddelanden, konsumenter vid mottagande och klient skickas när de etableras.
  • componentservicebus

Alla händelser har också egenskaper för entitet och slutpunkt. De utelämnas i tabellen nedan

  • string Entity – Namnet på entiteten (kö, ämne och så vidare.)
  • Uri Endpoint– Service Bus slutpunkts-URL

Instrumenterade åtgärder

Här är den fullständiga listan över instrumenterade åtgärder:

Åtgärdsnamn Spårat API
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 Processoråteranrop inställt på ServiceBusProcessor. Egenskapen ProcessMessageAsync
ServiceBusSessionProcessor.ProcessSessionMessage Processoråteranrop inställt på ServiceBusSessionProcessor. Egenskapen ProcessMessageAsync

Filtrering och sampling

I vissa fall är det önskvärt att endast logga en del av händelserna för att minska prestandakostnaderna eller lagringsförbrukningen. Du kan logga "Stoppa"-händelser endast (som i föregående exempel) eller exempelprocent av händelserna. DiagnosticSource ge möjlighet att uppnå det med IsEnabled predikat. Mer information finns i Kontextbaserad filtrering i DiagnosticSource.

IsEnabled kan anropas flera gånger för en enda åtgärd för att minimera prestandapåverkan.

IsEnabled anropas i följande sekvens:

  1. IsEnabled(<OperationName>, string entity, null) till exempel IsEnabled("ServiceBusSender.Send", "MyQueue1"). Observera att det inte finns någon "Start" eller "Stop" i slutet. Använd den för att filtrera bort vissa åtgärder eller köer. Om motringningsmetoden returnerar falseskickas inte händelser för åtgärden.

    • För åtgärderna Process och ProcessSession får IsEnabled(<OperationName>, string entity, Activity activity) du även återanrop. Använd den för att filtrera händelser baserat på activity.Id egenskaper eller Taggar.
  2. IsEnabled(<OperationName>.Start) till exempel IsEnabled("ServiceBusSender.Send.Start"). Kontrollerar om starthändelsen ska utlösas. Resultatet påverkar bara starthändelsen, men ytterligare instrumentation är inte beroende av den.

Det finns inget IsEnabled för "Stop"-händelsen.

Om något åtgärdsresultat är ett undantag IsEnabled("ServiceBusSender.Send.Exception") anropas. Du kan bara prenumerera på undantagshändelser och förhindra resten av instrumentationen. I det här fallet måste du fortfarande hantera sådana undantag. Eftersom annan instrumentation är inaktiverad bör du inte förvänta dig att spårningskontexten flödar med meddelanden från konsument till producent.

Du kan även använda IsEnabled samplingsstrategier. Sampling baserat på Activity.Id eller Activity.RootId säkerställer konsekvent sampling över alla däck (så länge det sprids genom spårningssystem eller med din egen kod).

Om det finns flera DiagnosticSource lyssnare för samma källa räcker det för bara en lyssnare att acceptera händelsen, så det finns ingen garanti som IsEnabled anropas.

Nästa steg