Udostępnij za pośrednictwem


Śledzenie rozproszone i korelacja za pośrednictwem obsługi wiadomości usługi Service Bus

Jednym z typowych problemów związanych z opracowywaniem mikrousług jest możliwość śledzenia operacji od klienta za pośrednictwem wszystkich usług, które są zaangażowane w przetwarzanie. Jest to przydatne w przypadku debugowania, analizy wydajności, testowania A/B i innych typowych scenariuszy diagnostycznych. Jedną z części tego problemu jest śledzenie logicznych elementów pracy. Obejmuje on wynik i opóźnienie przetwarzania komunikatów oraz wywołania zależności zewnętrznych. Inną częścią jest korelacja tych zdarzeń diagnostycznych poza granice procesu.

Gdy producent wysyła komunikat za pośrednictwem kolejki, zwykle występuje w zakresie innej operacji logicznej zainicjowanej przez innego klienta lub usługę. Ta sama operacja jest kontynuowana przez użytkownika po otrzymaniu komunikatu. Zarówno producent, jak i konsument (oraz inne usługi, które przetwarzają operację), prawdopodobnie emitują zdarzenia telemetryczne w celu śledzenia przepływu operacji i wyniku. Aby skorelować takie zdarzenia i kompleksową operację śledzenia, każda usługa, która raportuje dane telemetryczne, musi oznaczać każde zdarzenie kontekstem śledzenia. Jedną z bibliotek, które mogą pomóc deweloperom mieć wszystkie te dane telemetryczne emitowane domyślnie, jest NServiceBus.

Obsługa komunikatów usługi Microsoft Azure Service Bus ma zdefiniowane właściwości ładunku, których producenci i odbiorcy powinni używać do przekazywania takiego kontekstu śledzenia. Protokół jest oparty na kontekście śledzenia W3C.

Nazwa właściwości Opis
Identyfikator diagnostyczny Unikatowy identyfikator wywołania zewnętrznego od producenta do kolejki. Zapoznaj się z nagłówkem trace-context trace-context w formacie W3C

Autotracing klienta .NET usługi Service Bus

ServiceBusProcessor Klasa klienta usługi Azure Messaging Service Bus dla platformy .NET udostępnia punkty instrumentacji śledzenia, które można podłączyć przez systemy śledzenia lub fragment kodu klienta. Instrumentacja umożliwia śledzenie wszystkich wywołań usługi obsługi komunikatów usługi Service Bus po stronie klienta. Jeśli przetwarzanie komunikatów odbywa się przy użyciu ( ProcessMessageAsync wzorzec obsługi komunikatów), przetwarzanie komunikatów ServiceBusProcessor jest również instrumentowane.

Śledzenie za pomocą usługi aplikacja systemu Azure Insights

Usługa Microsoft Application Insights oferuje zaawansowane funkcje monitorowania wydajności, w tym automatyczne żądanie i śledzenie zależności.

W zależności od typu projektu zainstaluj zestaw SDK usługi Application Insights:

Jeśli używasz ProcessMessageAsync (wzorca obsługi komunikatów) do przetwarzania ServiceBusProcessor komunikatów, przetwarzanie komunikatów jest również instrumentowane. Wszystkie wywołania usługi Service Bus wykonywane przez usługę są automatycznie śledzone i skorelowane z innymi elementami telemetrii. W przeciwnym razie zapoznaj się z poniższym przykładem śledzenia ręcznego przetwarzania komunikatów.

Przetwarzanie komunikatów śledzenia

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

W tym przykładzie dane telemetryczne żądań są zgłaszane dla każdego przetworzonego komunikatu, mając znacznik czasu, czas trwania i wynik (powodzenie). Dane telemetryczne mają również zestaw właściwości korelacji. Zagnieżdżone ślady i wyjątki zgłaszane podczas przetwarzania komunikatów są również oznaczane właściwościami korelacji reprezentującymi je jako "elementy podrzędne" elementu RequestTelemetry.

W przypadku wykonywania wywołań do obsługiwanych składników zewnętrznych podczas przetwarzania komunikatów są one również automatycznie śledzone i skorelowane. Zapoznaj się z tematem Śledzenie operacji niestandardowych za pomocą zestawu SDK platformy .NET usługi Application Insights, aby uzyskać instrukcje ręcznego śledzenia i korelacji.

Jeśli używasz dowolnego kodu zewnętrznego oprócz zestawu SDK usługi Application Insights, spodziewaj się dłuższego czasu trwania podczas wyświetlania dzienników usługi Application Insights.

Dłuższy czas trwania w dzienniku usługi Application Insights

Nie oznacza to, że wystąpiło opóźnienie podczas odbierania komunikatu. W tym scenariuszu komunikat został już odebrany, ponieważ komunikat jest przekazywany jako parametr do kodu zestawu SDK. Tag nazwy w dziennikach usługi App Insights (proces) wskazuje, że komunikat jest teraz przetwarzany przez kod przetwarzania zdarzeń zewnętrznych. Ten problem nie jest związany z platformą Azure. Zamiast tego te metryki odnoszą się do wydajności kodu zewnętrznego, ponieważ komunikat został już odebrany z usługi Service Bus.

Śledzenie za pomocą funkcji OpenTelemetry

Biblioteka klienta .NET usługi Service Bus w wersji 7.5.0 lub nowszej obsługuje funkcję OpenTelemetry w trybie eksperymentalnym. Aby uzyskać więcej informacji, zobacz Śledzenie rozproszone w zestawie SDK platformy .NET.

Śledzenie bez systemu śledzenia

Jeśli system śledzenia nie obsługuje automatycznego śledzenia wywołań usługi Service Bus, możesz rozważyć dodanie takiej obsługi do systemu śledzenia lub do aplikacji. W tej sekcji opisano zdarzenia diagnostyczne wysyłane przez klienta .NET usługi Service Bus.

Klient .NET usługi Service Bus jest instrumentowany przy użyciu elementów pierwotnych śledzenia platformy .NET System.Diagnostics.Activity i System.Diagnostics.DiagnosticSource.

Activity służy jako kontekst śledzenia, podczas gdy DiagnosticSource jest mechanizmem powiadamiania.

Jeśli nie ma odbiornika zdarzeń DiagnosticSource, instrumentacja jest wyłączona, zachowując zerowe koszty instrumentacji. Narzędzie DiagnosticSource zapewnia całą kontrolę odbiornikowi:

  • odbiornik steruje źródłami i zdarzeniami do nasłuchiwania
  • odbiornik kontroluje częstotliwość zdarzeń i próbkowanie
  • zdarzenia są wysyłane z ładunkiem, który zapewnia pełny kontekst, dzięki czemu można uzyskać dostęp do obiektu komunikatu i zmodyfikować go podczas zdarzenia

Zapoznaj się z podręcznikiem użytkownika DiagnosticSource przed kontynuowaniem implementacji.

Utwórzmy odbiornik zdarzeń usługi Service Bus w aplikacji ASP.NET Core, która zapisuje dzienniki w pliku Microsoft.Extension.Logger. Używa biblioteki System.Reactive.Core do subskrybowania elementu DiagnosticSource (można również łatwo zasubskrybować źródło diagnostyczne bez niego)

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

W tym przykładzie odbiornik rejestruje czas trwania, wynik, unikatowy identyfikator i godzinę rozpoczęcia dla każdej operacji usługi Service Bus.

Zdarzenia

Wszystkie zdarzenia będą miały następujące właściwości zgodne ze specyfikacją otwartej telemetrii: https://github.com/open-telemetry/opentelemetry-specification/blob/master/specification/trace/api.md.

  • message_bus.destination — kolejka/temat/ścieżka subskrypcji
  • peer.address – w pełni kwalifikowana przestrzeń nazw
  • kind – producent, konsument lub klient. Producent jest używany podczas wysyłania komunikatów, odbiorcy podczas odbierania i klienta podczas ustalania.
  • componentservicebus

Wszystkie zdarzenia mają Entity również właściwości i Endpoint .

  • Entity — Nazwa jednostki (kolejka, temat itd.)
    • Endpoint — Adres URL punktu końcowego usługi Service Bus

Operacje instrumentowane

Oto pełna lista operacji instrumentowanych:

Nazwa operacji Śledzony interfejs 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 Wywołanie zwrotne procesora ustawione w usłudze ServiceBusProcessor. Właściwość ProcessMessageAsync
ServiceBusSessionProcessor.ProcessSessionMessage Wywołanie zwrotne procesora ustawione w usłudze ServiceBusSessionProcessor. Właściwość ProcessMessageAsync

Filtrowanie i próbkowanie

W niektórych przypadkach pożądane jest rejestrowanie tylko części zdarzeń w celu zmniejszenia obciążenia związanego z wydajnością lub zużycia magazynu. Można rejestrować tylko zdarzenia "Zatrzymaj" (jak w poprzednim przykładzie) lub przykładowy procent zdarzeń. DiagnosticSource zapewnić sposób osiągnięcia go z IsEnabled predykatem. Aby uzyskać więcej informacji, zobacz Filtrowanie oparte na kontekście w źródle diagnostycznym.

IsEnabled może być wywoływana wiele razy dla pojedynczej operacji w celu zminimalizowania wpływu na wydajność.

IsEnabled jest wywoływana w następującej sekwencji:

  1. IsEnabled(<OperationName>, string entity, null) na przykład IsEnabled("ServiceBusSender.Send", "MyQueue1"). Pamiętaj, że na końcu nie ma "Start" ani "Stop". Służy do filtrowania określonych operacji lub kolejek. Jeśli metoda wywołania zwrotnego zwraca falsewartość , zdarzenia dla operacji nie są wysyłane.

    • W przypadku operacji "Process" i "ProcessSession" otrzymasz IsEnabled(<OperationName>, string entity, Activity activity) również wywołanie zwrotne. Służy do filtrowania zdarzeń na activity.Id podstawie właściwości tagów lub .
  2. IsEnabled(<OperationName>.Start) na przykład IsEnabled("ServiceBusSender.Send.Start"). Sprawdza, czy zdarzenie "Start" powinno zostać wyzwolone. Wynik ma wpływ tylko na zdarzenie "Start", ale dalsza instrumentacja nie zależy od niego.

Nie ma IsEnabled zdarzenia "Zatrzymaj".

Jeśli jakiś wynik operacji jest wyjątkiem, IsEnabled("ServiceBusSender.Send.Exception") jest wywoływany. Można subskrybować tylko zdarzenia "Wyjątek" i zapobiegać pozostałej części instrumentacji. W takim przypadku nadal trzeba obsługiwać takie wyjątki. Ponieważ inne instrumentacje są wyłączone, nie należy oczekiwać, że kontekst śledzenia będzie przepływać z komunikatami od konsumenta do producenta.

Można również zaimplementować IsEnabled strategie próbkowania. Próbkowanie na Activity.Id podstawie metody lub Activity.RootId zapewnia spójne próbkowanie we wszystkich oponach (o ile jest propagowane przez system śledzenia lub własny kod).

W obecności wielu DiagnosticSource odbiorników dla tego samego źródła wystarczy, aby tylko jeden odbiornik zaakceptował zdarzenie, więc nie ma gwarancji, że IsEnabled jest wywoływany.

Następne kroki