دليل استكشاف الأخطاء وإصلاحها للمشكلات الشائعة لخدمة Azure SignalR

توفر هذه المقالة إرشادات استكشاف الأخطاء وإصلاحها لبعض المشكلات الشائعة التي قد يواجهها العملاء.

الرمز المميز للوصول طويل جدا

الأخطاء المحتملة

  • جانب العميل ERR_CONNECTION_
  • 414 URI طويل جدا
  • 413 حمولة كبيرة للغاية
  • يجب ألا يزيد الرمز المميز للوصول عن 4K. 413 كيان الطلب كبير جدًا

السبب الجذري

بالنسبة إلى HTTP/2، يكون الحد الأقصى للطول لعنوان واحد هو 4 كيلوبايت، لذلك إذا كان استخدام المستعرض للوصول إلى خدمة Azure، سيكون هناك خطأ ERR_CONNECTION_ لهذا القيد.

بالنسبة لعملاء HTTP/1.1 أو C#، يبلغ الحد الأقصى لطول URI 12 كيلوبايت، والحد الأقصى لطول العنوان هو 16 كيلوبايت.

مع إصدار SDK 1.0.6 أو أعلى، /negotiate سيتم طرح 413 Payload Too Large عندما يكون الرمز المميز للوصول الذي تم إنشاؤه أكبر من 4 K.

الحل

بشكل افتراضي، يتم تضمين المطالبات من context.User.Claims عند إنشاء رمز وصول JWT إلى ASRS (Azure SignalRService)، بحيث يتم الاحتفاظ بالمطالبات ويمكن تمريرها من ASRS إلى Hub عندما يتصل العميل ب Hub.

في بعض الحالات، context.User.Claims يتم استخدام لتخزين الكثير من المعلومات لخادم التطبيق، ومعظمها لا يتم استخدامه من قبل Hubs ولكن من قبل مكونات أخرى.

يتم تمرير الرمز المميز للوصول الذي تم إنشاؤه عبر الشبكة، وبالنسبة لاتصالات WebSocket/SSE، يتم تمرير رموز الوصول المميزة من خلال سلاسل الاستعلام. لذلك، وكأفضل ممارسة، نقترح تمرير المطالبات الضرورية فقط من العميل من خلال ASRS إلى خادم التطبيق الخاص بك عندما يحتاج Hub.

ClaimsProvider هناك لك لتخصيص المطالبات التي تمرر إلى ASRS داخل الرمز المميز للوصول.

بالنسبة إلى ASP.NET Core:

services.AddSignalR()
        .AddAzureSignalR(options =>
            {
                // pick up necessary claims
                options.ClaimsProvider = context => context.User.Claims.Where(...);
            });

على سبيل ASP.NET:

services.MapAzureSignalR(GetType().FullName, options =>
            {
                // pick up necessary claims
                options.ClaimsProvider = context.Authentication?.User.Claims.Where(...);
            });

هل تواجه مشكلات أو ملاحظات حول استكشاف الأخطاء وإصلاحها؟ أبلغنا بها.

TLS 1.2 مطلوب

الأخطاء المحتملة

  • ASP.NET الخطأ "لا يوجد خادم متوفر" #279
  • ASP.NET "الاتصال غير نشط، لا يمكن إرسال البيانات إلى الخدمة." الخطأ #324
  • "حدث خطأ أثناء إجراء طلب HTTP إلى https://<API endpoint>. قد يكون هذا الخطأ بسبب عدم تكوين شهادة الخادم بشكل صحيح مع HTTP.SYS في حالة HTTPS. قد يحدث هذا الخطأ أيضا بسبب عدم تطابق ربط الأمان بين العميل والخادم."

السبب الجذري

تدعم خدمة Azure TLS1.2 فقط لمخاوف الأمان. مع .NET framework، من الممكن أن TLS1.2 ليس البروتوكول الافتراضي. ونتيجة لذلك، لا يمكن إنشاء اتصالات الخادم ب ASRS بنجاح.

دليل استكشاف الأخطاء وإصلاحها

  1. إذا كان يمكن إعادة إنتاج هذا الخطأ محليا، فقم بإلغاء تحديد Just My Code وطرح كافة استثناءات CLR وتصحيح أخطاء خادم التطبيق محليا لمعرفة ما يطرحه الاستثناء.

    • إلغاء تحديد التعليمات البرمجية الخاصة بي فقط

      Uncheck Just My Code

    • طرح استثناءات CLR

      Throw CLR exceptions

    • راجع الاستثناءات التي يتم طرحها عند تصحيح أخطاء التعليمات البرمجية من جانب خادم التطبيق:

      Exception throws

  2. بالنسبة ASP.NET منها، يمكنك أيضا إضافة التعليمات البرمجية التالية إلى الخاص بك Startup.cs لتمكين التتبع التفصيلي ورؤية الأخطاء من السجل.

    app.MapAzureSignalR(this.GetType().FullName);
    // Make sure this switch is called after MapAzureSignalR
    GlobalHost.TraceManager.Switch.Level = SourceLevels.Information;
    

الحل

أضف التعليمات البرمجية التالية إلى بدء التشغيل:

ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;

هل تواجه مشكلات أو ملاحظات حول استكشاف الأخطاء وإصلاحها؟ أبلغنا بها.

تم إرجاع 400 طلب غير صحيح لطلبات العميل

السبب الجذري

تحقق مما إذا كان طلب العميل يحتوي على سلاسل استعلام متعددة hub . hub هو معلمة استعلام محفوظة وسيتم طرح 400 إذا اكتشفت الخدمة أكثر من واحد hub في الاستعلام.

هل تواجه مشكلات أو ملاحظات حول استكشاف الأخطاء وإصلاحها؟ أبلغنا بها.

401 تم إرجاع غير مصرح به لطلبات العميل

السبب الجذري

القيمة الافتراضية حاليا لعمر رمز JWT المميز هي ساعة واحدة (1).

بالنسبة إلى ASP.NET Core SignalR، عندما يستخدم نوع نقل WebSocket، فلا بأس.

بالنسبة ASP.NET نوع النقل الآخر ل Core SignalR، SSE والاستقصاء الطويل، فإن العمر الافتراضي يعني بشكل افتراضي أن الاتصال يمكن أن يستمر لمدة ساعة واحدة على الأكثر.

بالنسبة ASP.NET SignalR، يرسل /ping العميل طلب "البقاء على قيد الحياة" إلى الخدمة من وقت لآخر، وعندما /ping يفشل، يقوم العميل بإجهاض الاتصال ولا يعيد الاتصال أبدا. بالنسبة إلى ASP.NET SignalR، فإن عمر الرمز المميز الافتراضي يجعل الاتصال يستمر لمدة ساعة واحدة على الأكثر لجميع أنواع النقل.

الحل

بالنسبة إلى المخاوف الأمنية، لا يتم تشجيع توسيع TTL. نقترح إضافة منطق إعادة الاتصال من العميل لإعادة تشغيل الاتصال عند حدوث مثل هذا 401. عندما يعيد العميل تشغيل الاتصال، فإنه سيتفاوض مع خادم التطبيق للحصول على رمز JWT المميز مرة أخرى والحصول على رمز مميز مجدد.

تحقق هنا لمعرفة كيفية إعادة تشغيل اتصالات العميل.

هل تواجه مشكلات أو ملاحظات حول استكشاف الأخطاء وإصلاحها؟ أبلغنا بها.

تم إرجاع 404 لطلبات العميل

بالنسبة لاتصال SignalR المستمر، فإنه أولا /negotiate إلى خدمة Azure SignalR ثم ينشئ الاتصال الحقيقي بخدمة Azure SignalR.

دليل استكشاف الأخطاء وإصلاحها

  • باتباع كيفية عرض الطلبات الصادرة للحصول على الطلب من العميل إلى الخدمة.
  • تحقق من عنوان URL للطلب عند حدوث 404. إذا كان عنوان URL يستهدف تطبيق الويب الخاص بك، وعلى غرار {your_web_app}/hubs/{hubName}، تحقق مما إذا كان العميل SkipNegotiation هو true. يتلقى العميل عنوان URL لإعادة التوجيه عند التفاوض لأول مرة مع خادم التطبيق. يجب ألا يتخطى العميل التفاوض عند استخدام Azure SignalR.
  • يمكن أن يحدث 404 آخر عند معالجة طلب الاتصال بعد أكثر من خمس (5) ثوان بعد /negotiate استدعاء. تحقق من الطابع الزمني لطلب العميل، وافتح مشكلة لنا إذا كان الطلب إلى الخدمة يحتوي على استجابة بطيئة.

هل تواجه مشكلات أو ملاحظات حول استكشاف الأخطاء وإصلاحها؟ أبلغنا بها.

تم إرجاع 404 لطلب إعادة اتصال ASP.NET SignalR

على سبيل ASP.NET SignalR، عند انخفاض اتصال العميل، فإنه يعيد الاتصال باستخدام نفسه connectionId ثلاث مرات قبل إيقاف الاتصال. /reconnect يمكن أن يساعد إذا تم إسقاط الاتصال بسبب مشكلات متقطعة في الشبكة يمكن أن /reconnect تعيد إنشاء الاتصال المستمر بنجاح. في ظل ظروف أخرى، على سبيل المثال، يتم إسقاط اتصال العميل بسبب إسقاط اتصال الخادم الذي تم توجيهه، أو تحتوي خدمة SignalR على بعض الأخطاء الداخلية مثل إعادة تشغيل المثيل/تجاوز الفشل/النشر، ولم يعد الاتصال موجودا، وبالتالي /reconnect إرجاع 404. إنه السلوك المتوقع ل /reconnect وبعد ثلاث مرات إعادة محاولة توقف الاتصال. نقترح وجود منطق إعادة تشغيل الاتصال عند توقف الاتصال.

هل تواجه مشكلات أو ملاحظات حول استكشاف الأخطاء وإصلاحها؟ أبلغنا بها.

429 (طلبات كثيرة جدا) تم إرجاعها لطلبات العميل

هناك حالتان.

عدد الاتصالات المتزامنة يتجاوز الحد

بالنسبة للمثيلات المجانية، يكون حد عدد الاتصالات المتزامنة 20 للمثيلات القياسية، والحد الأقصى لعدد الاتصالات المتزامنة لكل وحدة هو 1 كيلوبايت، مما يعني أن Unit100 يسمح باتصالات متزامنة 100 كيلوبايت.

تتضمن الاتصالات اتصالات العميل والخادم. تحقق هنا من كيفية حساب الاتصالات.

عدد كبير جدا من طلبات التفاوض في نفس الوقت

نقترح وجود تأخير عشوائي قبل إعادة الاتصال، تحقق هنا للحصول على عينات إعادة المحاولة.

هل تواجه مشكلات أو ملاحظات حول استكشاف الأخطاء وإصلاحها؟ أبلغنا بها.

500 خطأ عند التفاوض: خدمة Azure SignalR غير متصلة بعد، يرجى المحاولة مرة أخرى لاحقا

السبب الجذري

يتم الإبلاغ عن هذا الخطأ عند عدم وجود اتصال خادم بخدمة Azure SignalR.

دليل استكشاف الأخطاء وإصلاحها

تمكين التتبع من جانب الخادم لمعرفة تفاصيل الخطأ عندما يحاول الخادم الاتصال بخدمة Azure SignalR.

تمكين التسجيل من جانب الخادم ل ASP.NET Core SignalR

يتكامل التسجيل من جانب الخادم ASP.NET Core SignalR مع ILogger التسجيل المستند إلى المتوفر في إطار عمل ASP.NET Core. يمكنك تمكين التسجيل من جانب الخادم باستخدام ConfigureLogging، نموذج استخدام كما يلي:

.ConfigureLogging((hostingContext, logging) =>
        {
            logging.AddConsole();
            logging.AddDebug();
        })

تبدأ فئات المسجل ل Azure SignalR دائما ب Microsoft.Azure.SignalR. لتمكين السجلات التفصيلية من Azure SignalR، قم بتكوين البادئات السابقة إلى Debug مستوى في ملف appsettings.json الخاص بك كما يلي:

{
    "Logging": {
        "LogLevel": {
            ...
            "Microsoft.Azure.SignalR": "Debug",
            ...
        }
    }
}

تمكين التتبعات من جانب الخادم ASP.NET SignalR

عند استخدام إصدار >SDK = 1.0.0، يمكنك تمكين التتبعات عن طريق إضافة ما يلي إلى web.config: (التفاصيل)

<system.diagnostics>
    <sources>
      <source name="Microsoft.Azure.SignalR" switchName="SignalRSwitch">
        <listeners>
          <add name="ASRS" />
        </listeners>
      </source>
    </sources>
    <!-- Sets the trace verbosity level -->
    <switches>
      <add name="SignalRSwitch" value="Information" />
    </switches>
    <!-- Specifies the trace writer for output -->
    <sharedListeners>
      <add name="ASRS" type="System.Diagnostics.TextWriterTraceListener" initializeData="asrs.log.txt" />
    </sharedListeners>
    <trace autoflush="true" />
  </system.diagnostics>

هل تواجه مشكلات أو ملاحظات حول استكشاف الأخطاء وإصلاحها؟ أبلغنا بها.

قطرات اتصال العميل

عندما يكون العميل متصلا ب Azure SignalR، يمكن أن ينخفض الاتصال المستمر بين العميل وAzure SignalR أحيانا لأسباب مختلفة. يصف هذا القسم العديد من الاحتمالات التي تسبب انخفاض الاتصال هذا ويوفر بعض الإرشادات حول كيفية تحديد السبب الجذري.

الأخطاء المحتملة التي شوهدت من جانب العميل

  • The remote party closed the WebSocket connection without completing the close handshake
  • Service timeout. 30000.00ms elapsed without receiving a message from service.
  • {"type":7,"error":"Connection closed with an error."}
  • {"type":7,"error":"Internal server error."}

السبب الجذري

يمكن أن تنخفض اتصالات العميل في ظل ظروف مختلفة:

  • عند Hub طرح استثناءات مع الطلب الوارد
  • عندما ينخفض اتصال الخادم، الذي وجه العميل إليه، راجع القسم أدناه للحصول على تفاصيل حول انخفاض اتصال الخادم
  • عندما تحدث مشكلة في اتصال الشبكة بين العميل وخدمة SignalR
  • عندما تحتوي SignalR Service على بعض الأخطاء الداخلية مثل إعادة تشغيل المثيل وتجاوز الفشل والنشر وما إلى ذلك

دليل استكشاف الأخطاء وإصلاحها

  1. افتح سجل التطبيق من جانب الخادم لمعرفة ما إذا كان قد حدث أي شيء غير طبيعي
  2. تحقق من سجل الأحداث من جانب خادم التطبيق لمعرفة ما إذا كان خادم التطبيق قد تمت إعادة تشغيله
  3. إنشاء مشكلة لنا لتوفير الإطار الزمني، وإرسال اسم المورد إلينا بالبريد الإلكتروني

هل تواجه مشكلات أو ملاحظات حول استكشاف الأخطاء وإصلاحها؟ أبلغنا بها.

يزداد اتصال العميل باستمرار

قد يكون سببه الاستخدام غير السليم لاتصال العميل. إذا نسي شخص ما إيقاف/التخلص من عميل SignalR، يبقى الاتصال مفتوحا.

الأخطاء المحتملة التي تظهر من مقاييس SignalR الموجودة في قسم المراقبة من قائمة موارد مدخل Microsoft Azure

ترتفع اتصالات العميل باستمرار لفترة طويلة في مقاييس Azure SignalR.

Client connection increasing constantly

السبب الجذري

لا يتم استدعاء اتصال DisposeAsync عميل SignalR أبدا، يظل الاتصال مفتوحا.

دليل استكشاف الأخطاء وإصلاحها

تحقق مما إذا كان عميل SignalR لا يغلق أبدا .

الحل

تحقق مما إذا كنت تغلق الاتصال. استدعاء HubConnection.DisposeAsync() يدويا لإيقاف الاتصال بعد استخدامه.

على سبيل المثال:

var connection = new HubConnectionBuilder()
	.WithUrl(...)
	.Build();
try
{
	await connection.StartAsync();
	// Do your stuff
	await connection.StopAsync();
}
finally
{
	await connection.DisposeAsync();
}

استخدام اتصال العميل غير السليم الشائع

مثال دالة Azure

غالبا ما تحدث هذه المشكلة عندما يقوم شخص ما بإنشاء اتصال عميل SignalR في أسلوب Azure Function بدلا من جعله عضوا ثابتا في فئة الدالة. قد تتوقع إنشاء اتصال عميل واحد فقط، ولكن بدلا من ذلك ترى أن عدد اتصال العميل يزيد باستمرار في المقاييس. تسقط جميع هذه الاتصالات فقط بعد إعادة تشغيل خدمة Azure Function أو Azure SignalR. هذا السلوك لأنه لكل طلب، تنشئ Azure Function اتصال عميل واحد، وإذا لم توقف اتصال العميل في أسلوب الدالة، يحتفظ العميل بالاتصالات على قيد الحياة بخدمة Azure SignalR.

الحل

هل تواجه مشكلات أو ملاحظات حول استكشاف الأخطاء وإصلاحها؟ أبلغنا بها.

قطرات اتصال الخادم

عند بدء تشغيل خادم التطبيق، في الخلفية، يبدأ Azure SDK في بدء اتصالات الخادم ب Azure SignalR البعيد. كما هو موضح في الأجزاء الداخلية لخدمة Azure SignalR، يوجه Azure SignalR حركة مرور العميل الواردة إلى اتصالات الخادم هذه. بمجرد إسقاط اتصال الخادم، سيتم إغلاق جميع اتصالات العميل التي يخدمها أيضا.

نظرا لأن الاتصالات بين خادم التطبيق وخدمة SignalR هي اتصالات مستمرة، فقد تواجه مشكلات في اتصال الشبكة. في Server SDK، لدينا استراتيجية إعادة الاتصال دائما باتصالات الخادم. كأفضل ممارسة، نشجع المستخدمين أيضا على إضافة منطق إعادة الاتصال المستمر للعملاء مع وقت تأخير عشوائي لتجنب الطلبات المتزامنة الضخمة إلى الخادم.

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

يصف هذا القسم العديد من الاحتمالات التي تؤدي إلى انخفاض اتصال الخادم، ويوفر بعض الإرشادات حول كيفية تحديد السبب الجذري.

الأخطاء المحتملة التي تظهر من جانب الخادم

  • [Error]Connection "..." to the service was dropped
  • The remote party closed the WebSocket connection without completing the close handshake
  • Service timeout. 30000.00ms elapsed without receiving a message from service.

السبب الجذري

يتم إغلاق اتصال خدمة الخادم بواسطة ASRS (Azure SignalRService).

لمهلة اختبار اتصال، قد يكون سبب ذلك ارتفاع استخدام وحدة المعالجة المركزية أو تجويع تجمع مؤشر الترابط على جانب الخادم.

بالنسبة إلى ASP.NET SignalR، تم إصلاح مشكلة معروفة في SDK 1.6.0. ترقية SDK إلى أحدث إصدار.

تجويع تجمع مؤشر الترابط

إذا كان الخادم الخاص بك يتضور جوعا، فهذا يعني أنه لا توجد مؤشرات ترابط تعمل على معالجة الرسائل. لا تستجيب جميع مؤشرات الترابط بطريقة معينة.

عادة ما يحدث هذا السيناريو بسبب التزامن عبر المزامنة أو في Task.Result/Task.Wait() أساليب غير متزامنة.

راجع ASP.NET أفضل ممارسات الأداء الأساسية.

تعرف على المزيد حول تجويع تجمع مؤشر الترابط.

كيفية الكشف عن تجويع تجمع مؤشر الترابط

تحقق من عدد مؤشرات الترابط. إذا لم تكن هناك طفرات في ذلك الوقت، فاتخذ الخطوات التالية:

  • إذا كنت تستخدم Azure App Service، فتحقق من عدد مؤشرات الترابط في المقاييس. تحقق من Max التجميع:

    Screenshot of the Max thread count pane in Azure App Service.

  • إذا كنت تستخدم .NET Framework، يمكنك العثور على مقاييس في مراقبة الأداء في الجهاز الظاهري للخادم.

  • إذا كنت تستخدم .NET Core في حاوية، فشاهد تجميع التشخيصات في حاويات.

يمكنك أيضا استخدام التعليمات البرمجية للكشف عن تجويع تجمع مؤشر الترابط:

public class ThreadPoolStarvationDetector : EventListener
{
    private const int EventIdForThreadPoolWorkerThreadAdjustmentAdjustment = 55;
    private const uint ReasonForStarvation = 6;

    private readonly ILogger<ThreadPoolStarvationDetector> _logger;

    public ThreadPoolStarvationDetector(ILogger<ThreadPoolStarvationDetector> logger)
    {
        _logger = logger;
    }

    protected override void OnEventSourceCreated(EventSource eventSource)
    {
        if (eventSource.Name == "Microsoft-Windows-DotNETRuntime")
        {
            EnableEvents(eventSource, EventLevel.Informational, EventKeywords.All);
        }
    }

    protected override void OnEventWritten(EventWrittenEventArgs eventData)
    {
        // See: https://learn.microsoft.com/dotnet/framework/performance/thread-pool-etw-events#threadpoolworkerthreadadjustmentadjustment
        if (eventData.EventId == EventIdForThreadPoolWorkerThreadAdjustmentAdjustment &&
            eventData.Payload[2] as uint? == ReasonForStarvation)
        {
            _logger.LogWarning("Thread pool starvation detected!");
        }
    }
}

أضفه إلى خدمتك:

service.AddSingleton<ThreadPoolStarvationDetector>();

ثم تحقق من السجل الخاص بك عند قطع اتصال الخادم عن طريق مهلة اختبار الاتصال.

كيفية العثور على السبب الجذري لتجويع تجمع مؤشر الترابط

للعثور على السبب الجذري لتجويع تجمع مؤشر الترابط:

  • تفريغ الذاكرة، ثم تحليل مكدس الاستدعاءات. لمزيد من المعلومات، راجع تجميع وتحليل تفريغ الذاكرة.
  • استخدم clrmd لتفريغ الذاكرة عند اكتشاف تجويع تجمع مؤشر الترابط. ثم سجل مكدس الاستدعاءات.

دليل استكشاف الأخطاء وإصلاحها

  1. افتح سجل التطبيق من جانب الخادم لمعرفة ما إذا كان قد حدث أي شيء غير طبيعي.
  2. تحقق من سجل الأحداث من جانب خادم التطبيق لمعرفة ما إذا كان خادم التطبيق قد تمت إعادة تشغيله.
  3. إنشاء مشكلة. قم بتوفير الإطار الزمني، وإرسال اسم المورد إلينا بالبريد الإلكتروني.

هل تواجه مشكلات أو ملاحظات حول استكشاف الأخطاء وإصلاحها؟ أبلغنا بها.

تلميحات

كيفية عرض الطلب الصادر من العميل؟

خذ ASP.NET Core واحدا على سبيل المثال (ASP.NET واحد مشابه):

  • من المستعرض: خذ Chrome كمثال، يمكنك استخدام F12 لفتح نافذة وحدة التحكم، والتبديل إلى علامة تبويب الشبكة . قد تحتاج إلى تحديث الصفحة باستخدام F5 لالتقاط الشبكة من البداية.

    Chrome View Network

  • من عميل C#‎:

    يمكنك عرض حركات مرور الويب المحلية باستخدام Fiddler. يتم دعم حركة مرور WebSocket منذ Fiddler 4.5.

    Fiddler View Network

كيفية إعادة تشغيل اتصال العميل؟

فيما يلي نماذج التعليمات البرمجية التي تحتوي على إعادة تشغيل منطق الاتصال باستخدام استراتيجية إعادة المحاولة دائما:

هل تواجه مشكلات أو ملاحظات حول استكشاف الأخطاء وإصلاحها؟ أبلغنا بها.

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

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