تتبع الموزعة والارتباط من خلال المراسلة Service Bus

واحدة من المشاكل الشائعة في تطوير الخدمات الصغيرة هي القدرة على تتبع العملية من العميل من خلال جميع الخدمات المشاركة في المعالجة. من المفيد تصحيح الأخطاء وتحليل الأداء واختبار A/B وسيناريوهات التشخيص النموذجية الأخرى. أحد أجزاء هذه المشكلة هو تتبع قطعة منطقية من العمل. وهذا يتضمن نتيجة معالجة الرسائل وزمن الانتقال واستدعاءات التبعية الخارجية. جزء آخر هو ارتباط هذه الأحداث التشخيصية بما يتجاوز حدود العملية.

عندما يرسل منتج رسالة عبر قائمة انتظار، يحدث ذلك عادة في نطاق بعض العمليات المنطقية الأخرى، التي بدأها عميل أو خدمة أخرى. يتم مواصلة نفس العملية من قبل المستهلك بمجرد أن يتلقى رسالة. ومن المفترض أن يقوم كل من المنتج والمستهلك (والخدمات الأخرى التي تعالج العملية) ببعث أحداث telemetry لتتبع تدفق العملية ونتيجتها. من أجل ربط مثل هذه الأحداث وتتبع العملية الشاملة، كل خدمة تقرر أنه يجب علي telemetry أن توفر خوادم مخصصة القياس لكل حدث مع سياق التتبع.

وقد حددت رسائل Microsoft Azure Service Bus خصائص البيانات الأساسية التي ينبغي أن يستخدمها المنتجون والمستهلكون لتمرير سياق التتبع. يعتمد البروتوكول على W3C Trace-Context.

اسم الخاصية ‏‏الوصف
معرف التشخيص المعرف الفريد للاستدعاءات الخارجية من المنتج إلى قائمة الانتظار. ارجع إلى عنوان التتبع W3C Trace-Context للحصول على التنسيق

تعقب عميل Service Bus .NET

ServiceBusProcessorتوفر فئة عميل Azure Messaging Service Bus لـ .NET نقاط أدوات التتبع التي يمكن ربطها بواسطة أنظمة التتبع أو قطعة من التعليمات البرمجية للعميل. يسمح الجهاز بتتبع كافة الاستدعاءات إلى خدمة المراسلة Service Bus من جانب العميل. إذا تمت معالجة الرسائل باستخدام ProcessMessageAsync من ServiceBusProcessor (نمط معالج الرسالة) ، يتم أيضًا وضع علامة علي معالجة الرسالة.

التعقب باستخدام Azure Application Insights

يوفر Microsoft Application Insights قدرات مراقبة الأداء الغنية بما في ذلك طلب تلقائي وتعقب التبعية.

اعتمادًا على نوع المشروع، «install» عدة تطوير برامج Application Insights:

إذا استخدمتProcessMessageAsyncمنServiceBusProcessor (نمط معالج الرسالة) لمعالجة الرسائل، يتم أيضًا وضع علامة على معالجة الرسالة. يتم تعقب جميع استدعاءات Service Bus التي تم إجراؤها بواسطة الخدمة تلقائيًّا وترتبط بعناصر telemetry الأخرى. وإلا بالإشارة إلى المثال التالي لتعقب معالجة الرسائل اليدوية.

تعقب معالجة الرسائل

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

في هذا المثال، يتم الإبلاغ عن telemetry لكل رسالة تمت معالجتها، ذات طابع زمني ومدة ونتيجة (نجاح). يحتوي telemetry أيضًا على مجموعة من خصائص الارتباط. يتم أيضًا ختم عمليات التتبع والاستثناءات المتداخلة التي تم الإبلاغ عنها أثناء معالجة الرسالة بخصائص الارتباط التي تمثلها كـ "توابع" لـRequestTelemetry

في حالة قيامك باستدعاءاتك إلى المكونات الخارجية المعتمدة أثناء معالجة الرسائل، يتم تعقبها وربطها تلقائيًّا. الرجوع إلى تعقب العمليات المخصصة مع عدة تطوير برامج Application Insights .NET للتعقب اليدوي والارتباط.

إذا كنت تقوم بتشغيل أية تعليمات برمجية خارجية بالإضافة إلى عدة تطوير برامج التطبيق Application Insights SDK، تتوقع مدة أطول عند عرض سجلات Application Insights.

Longer duration in Application Insights log

هذا لا يعني أنه إذا كان هناك تأخير في تلقي الرسالة. في هذا السيناريو، تم استلام الرسالة بالفعل منذ تمرير الرسالة كمعلمة إلى التعليمة البرمجية SDK وعلامة الاسم في سجلات App Insights(العملية)يشير إلى أن الرسالة الآن يتم معالجتها بواسطة رمز معالجة الأحداث الخارجية. هذه المشكلة غير متعلقة بـ Azure. بدلًا من ذلك، تشير هذه المقاييس إلى كفاءة التعليمات البرمجية الخارجية الخاصة بك نظرًا لأن الرسالة قد تم استلامها بالفعل من Service Bus.

التتبع باستخدام OpenTelemetry

يدعم الإصدار 7.5.0 من مكتبة عميل .NET لناقل الخدمة والإصدارات الأحدث OpenTelemetry في الوضع التجريبي. لمزيد من المعلومات، راجع التتبع الموزع في .NET SDK.

التتبع بدون تتبع النظام

في حالة عدم دعم نظام التتبع الخاص بك لتتبع استدعاءات Service Bus التلقائية، قد تبحث عن إضافة هذا الدعم إلى نظام تتبع أو إلى التطبيق الخاص بك. يصف هذا المقطع أحداث التشخيص المرسلة بواسطة عميل Service Bus .NET

يضع عميل Service Bus .NET علامة باستخدام أساسيات تتبع .NET وهيSystem.Diagnostics.Activity و System.Diagnostics.DiagnosticSource.

Activity يعمل كسياق تتبع بينما DiagnosticSource هو آلية إعلام.

إذا لم يكن هناك وحدة استماع لأحداث DiagnosticSource ، فإن الأجهزة مطفأة، مع الاحتفاظ بتكاليف الأجهزة صفر. يوفر DiagnosticSource عنصر تحكم إلى وحدة الاستماع:

  • يتحكم المستمع في المصادر والأحداث التي يجب الاستماع إليها
  • تقوم عناصر بالتحكم في معدل الحدث وأخذ العينات
  • يتم إرسال الأحداث بالبيانات الأساسية التي توفر السياق الكامل بحيث يمكنك الوصول إلى كائن الرسالة وتعديلها أثناء الحدث

تعرف على دليل مستخدم DiagnosticSource قبل المتابعة في التنفيذ.

فلنعمل على إنشاء وحدة الاستماع لأحداث Service Bus في تطبيقات ASP.NET التي تكتب السجلات باستخدام Microsoft.Extension.Logger. ويستخدم مكتبة System.Reactive.Core للاشتراك في DiagnosticSource (كما أنه من السهل أيضًا الاشتراك في DiagnosticSource بدونها)

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

في هذا المثال، مدة تسجيلات وحدة الاستماع والنتيجة والمعرف الفريد ووقت بدء كل عملية Service Bus.

الأحداث

سيكون لكافة الأحداث الخصائص التالية التي تتوافق مع مواصفات بيانات تتبع الاستخدام المفتوحة: https://github.com/open-telemetry/opentelemetry-specification/blob/master/specification/trace/api.md .

  • message_bus.destination- مسار قائمة الانتظار/ الموضوع/ الاشتراك
  • peer.address- مساحة اسم مؤهلة بالكامل
  • kind- إما منتج أو عميل أو مستهلك يُستخدم المنتج عند إرسال الرسائل، والمستهلك عند الاستلام والعميل عند التسوية.
  • componentservicebus

تحتوي جميع الأحداث أيضا على Entity خصائص و Endpoint .

  • Entity - - اسم الكيان (قائمة الانتظار والموضوع وما إلى ذلك.)
  • Endpoint - «URL» نقطة نهاية Service Bus

العمليات التي تم وضع علامة عليها

فيما يلي القائمة الكاملة للعمليات التي تم وضع علامات عليها:

اسم العملية 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 callback set on ServiceBusProcessor. خاصية ProcessMessageAsync
ServiceBusSessionProcessor.ProcessSessionMessage تعيين استدعاء المعالج في ServiceBusSessionProcessor. خاصية ProcessMessageAsync

التصفية وأخذ عينات

في بعض الحالات، من المستحسن تسجيل جزء فقط من الأحداث لتقليل حمل الأداء أو استهلاك التخزين. يمكنك تسجيل أحداث 'Stop' فقط (كما في المثال السابق) أو عينة من الأحداث. DiagnosticSource توفير طريقة لتحقيق ذلك مع IsEnabled المسند. لمزيد من المعلومات، راجع التصفية المستندة إلى السياق في DiagnosticSource.

IsEnabled قد يتم الاستدعاء عدة مرات لعملية واحدة لتقليل تأثير الأداء.

يتم استدعاء IsEnabledفي التسلسل التالي:

  1. IsEnabled(<OperationName>, string entity, null)على سبيل المثال،IsEnabled("ServiceBusSender.Send", "MyQueue1"). لاحظ أنه لا يوجد 'Start' أو 'Stop' في النهاية. استخدامه لتصفية عمليات معينة أو قوائم الانتظار. إذا كان أسلوب رد الاتصال بإرجاعfalse، لا يتم إرسال الأحداث للعملية.

    • بالنسبة لعمليات 'Process' و'ProcessSession' ، تتلقى أيضًا IsEnabled(<OperationName>, string entity, Activity activity) رد الاتصال. استخدامه لتصفية الأحداث استنادًا إلى activity.Id أو خصائص العلامات.
  2. IsEnabled(<OperationName>.Start)على سبيل المثال،IsEnabled("ServiceBusSender.Send.Start"). التحقق مما إذا كان يجب تشغيل حدث "Start". تؤثر النتيجة فقط على حدث "Start"، ولكن لا تعتمد عليه أجهزة أخرى.

لا يوجد IsEnabled لحدث "Stop".

إذا كانت بعض نتائج العملية استثناء، يتم استدعاءIsEnabled("ServiceBusSender.Send.Exception"). يمكنك الاشتراك فقط في أحداث "Exception" ومنع بقية الأجهزة. في هذه الحالة، لا يزال يتعين عليك التعامل مع مثل هذه الاستثناءات. حيث إن الأجهزة الأخرى معطلة، فلا يجب أن تتوقع تدفق سياق التتبع مع الرسائل من المستهلك إلى المنتج.

يمكنك أيضًا استخدام IsEnabled وتنفيذ إستراتيجيات أخذ العينات. أخذ العينات على أساس Activity.Id أو يضمن أخذ عينات Activity.RootId متسقة عبر جميع الإطارات (طالما أنها تنتشر عن طريق نظام التتبع أو من قبل التعليمات البرمجية الخاصة بك).

في وجود DiagnosticSource وحدات استماع متعددة لنفس المصدر، يكفي لوحدة استماع واحدة قبول الحدث، لذلك ليس هناك ضمان يسمىIsEnabled.

الخطوات التالية